MonatKommit Februat

This commit is contained in:
jopster 2026-02-13 10:18:38 +01:00
parent d416043bf7
commit 9c218ba3aa
1981 changed files with 605021 additions and 204 deletions

View File

@ -54,7 +54,14 @@
'views/company_view.xml',
'views/google_map.xml',
'views/dss_report_invoice.xml',
'views/dss_crm_extended.xml',
'views/dss_kileads_requests.xml',
'views/dss_kileads.xml',
'data/ir_model_data.xml',
'views/dss_res_users_extended.xml',
'views/dss_web_contracts_all_templates.xml',
'views/dss_contract_uservars.xml',
'views/dss_portal_add.xml',
#'views/dss_screendesign.xml',
],
'demo': [],
@ -91,9 +98,10 @@
'DigitalSignage/static/src/js/dss_tagclick.js',
'DigitalSignage/static/src/js/form_button.js',
'DigitalSignage/static/src/js/kanban_button.js',
'DigitalSignage/static/src/js/dss_klistmanager.js',
'DigitalSignage/static/src/js/screenDesignerViewReload.js',
'DigitalSignage/static/src/js/dss_crm_extended_ki_leads.js',
'DigitalSignage/static/src/js/kilead_hook.js',
'DigitalSignage/static/src/xml/form_button.xml',
'DigitalSignage/static/src/xml/kanban_button.xml',
'DigitalSignage/static/src/xml/form_label.xml',
'DigitalSignage/static/src/js/test.php',
],
@ -102,6 +110,7 @@
'DigitalSignage/static/src/js/screenDesignerView.js',
'DigitalSignage/static/src/css/dss.css',
'DigitalSignage/static/src/scss/style.scss',
'DigitalSignage/static/src/js/dss_form_submit.js',
],
'web.assets_fontend': [
'DigitalSignage/static/src/js/dss_screenview_injector.js',

View File

@ -5,3 +5,4 @@ from . import main
from . import dss_screendesigner_controller
from . import dss_screenview_controller
from . import dss_nextcloudwidget
from . import dss_form_input_controller

BIN
controllers/__pycache__/__init__.cpython-311.pyc Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,328 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import os
import os.path
import base64
import logging
import werkzeug
import datetime
import json
from odoo.addons.portal.controllers import portal
from odoo.http import request,Controller, route
from werkzeug.wrappers import Response
from ..models.dss_contract import dsscontracts
from odoo import fields, http, _
_logger = logging.getLogger(__name__)
#class WebContractsInput(Controller):
class CustomerPortal(portal.CustomerPortal):
@route(['/eingabe'],type='http', auth='user', website=True, csrf=False)
def web_form(self, **kwargs):
_logger.info("inside: start web_form")
return request.render("website.eingabe-phase1")
@route(['/my/invoiceinput'],type='http', auth='user', website=True, csrf=False)
def ad_portal_my_documents(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='all', groupby='none', **kwargs):
values = super()._prepare_home_portal_values({})
user = request.env.user
Attachment = request.env['dss.contracts'].sudo()
domain = [('contract_state', '=', 39),
('contract_creator', '=', user.id),
('web_contract_input_notfinished','=',True)]
documents = Attachment.search(domain)
grouped_documents = []
if documents:
grouped_documents = [documents]
values.update({
'grouped_documents': grouped_documents,
'documents': documents.sudo(),
'username':user.name,
'page_name': 'Kundenvertraege',
'base_url': http.request.env["ir.config_parameter"].sudo().get_param("web.base.url"),
'default_url': '/my/invoiceinput'
})
return request.render("DigitalSignage.portal_my_invoiceinput", values)
@route(['/eingabe/start'],type='http', auth='user', website=True, csrf=False)
def changeScreenView(self, **kwargs):
_logger.info("inside start: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
user_id = request.env.user
projekt_id = kwargs.get('project')
project = request.env['dss.projects'].search([('id','=',int(projekt_id))],limit=1)
project.reservedkdnr=str(project.reservedkdnr)+';'+str(project.lastkdnr+1)
project.lastkdnr=project.lastkdnr+1
tempid = str(project.projectid) + str(user_id.id).zfill(2) + str(project.lastkdnr).zfill(2)
tempname = tempid + '_Vertrag'
contract_name = str(tempid)+' - Vertrag ' + str(project.lastkdnr).zfill(2)
contract_id = str(project.projectid) + str(project.lastrealkdnr).zfill(2)
grundsystem_webinput_template=project.web_input_template
if not grundsystem_webinput_template:
grundsystem_webinput_template = project.grundsystem_webinput_template
if not grundsystem_webinput_template:
return request.render("website.eingabe-phase2-notemplate",{'websideusername':name,'user_id':str(user_id.id)})
else:
new_contract = request.env['dss.contracts'].create({'project_id':project.projectid,'project':project.id,'client_id':str(project.lastkdnr).zfill(2),'contract_auto_id':str(tempid),'contract_auto_name':str(tempname),'contract_state':39,'contract_name':contract_name,'web_contract_input_notfinished':True,'contract_creator':int(user_id.id)})
contract_data_id=new_contract.id
_logger.info("inside start: "+str(name)+'--'+str(projekt_id)+'--'+str(grundsystem_webinput_template))
return request.render("website."+grundsystem_webinput_template,{'websideusername':name,'user_id':str(user_id.id),'projectid':str(project.projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(str(project.lastrealkdnr).zfill(2)),'web_contract_paysum_gfx':'249','contract_data_id':str(contract_data_id)})
@route(['/eingabe/continue'],type='http', auth='user', website=True, csrf=False)
def inputcontinue(self, **kwargs):
_logger.info("inside continue: " + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
user_id = request.env.user
contract = request.env['dss.contracts'].search([('uuid','=',kwargs.get('uuid'))],limit=1)
project = contract.project
_logger.info("inside continue: "+str(contract.contract_auto_name)+'--'+str(project.id))
grundsystem_webinput_template=project.web_input_template
if not grundsystem_webinput_template:
grundsystem_webinput_template = project.grundsystem_webinput_template
_logger.info("inside continue: "+str(contract.contract_auto_name)+'--'+str(project.id)+'--'+str(grundsystem_webinput_template))
felder = request.env['dss.advertisefields'].search(['&','|',('contract','=',False),('isblocked','=',False),('project','=',project.id)])
fo =""
sfeld =""
for feld in felder:
fo = fo+"<option value=''>"+feld.feldname+"</option>"
for feld in contract.werbe_feld_selected:
sfeld = sfeld+feld.auto_feldname+", "
evtlcontract_id = str(contract.project.projectid) + str(contract.project.lastrealkdnr).zfill(2)
evtlcontract_name = str(evtlcontract_id)+'_'+str(contract.client_short_company) if contract.client_short_company else str(contract.client_short_name)+' '+str(contract.client_short_vorname)
olddata = {
'user_id':str(user_id),
'projectid':str(project.projectid),
'project':str(project.id),
'contract_id':str(evtlcontract_id),
'client_short_company':str(contract.client_short_company),
'client_short_strasse':str(contract.client_short_strasse),
'client_short_plz':str(contract.client_short_plz),
'client_short_telefon':str(contract.client_short_telefon),
'client_short_email':str(contract.client_short_email),
'client_short_rgemail':str(contract.client_short_rgemail),
'client_short_ort':str(contract.client_short_ort),
'client_short_mobil':str(contract.client_short_mobil),
'client_short_website':str(contract.client_short_website),
'client_short_vorname':str(contract.client_short_vorname),
'client_short_name':str(contract.client_short_name),
'web_contract_paysum_lz':contract.web_contract_paysum_lz,
'web_contract_paysum_all':contract.web_contract_paysum_all,
'web_contract_paysum_gfx':contract.web_contract_paysum_gfx,
'contract_data_id':str(contract.id),
'feldoptions':fo,
'feldselected':sfeld,'kd_id':evtlcontract_name,
'Datum': contract.web_contract_sign_datum,
'Ort': contract.web_contract_sign_ort,
'NameVorname': contract.web_contract_sign_name,
'bic': contract.client_short_BIC,
'iban': contract.client_short_IBAN,
'kapay': contract.web_contract_kapayment_info,
'alpay': contract.web_contract_alpayment_info,
'sonder_0': contract.web_contract_sonder_0,
'sonder_1': contract.web_contract_sonder_1,
'sonder_2': contract.web_contract_sonder_2,
}
return request.render("website."+grundsystem_webinput_template, olddata)
@route(['/eingabe/finish'],type='http', auth='user', website=True, csrf=False)
def finish_contract(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
uuid = kwargs.get('uuid')
contract = request.env['dss.contracts'].search([('uuid','=',uuid)],limit=1)
_logger.info("inside finish_contract: "+str(contract.id)+'--'+str(contract.contract_auto_id)+'--'+str(uuid))
contract.web_contract_input_notfinished=False
contract_id = str(contract.project.projectid) + str(contract.project.lastrealkdnr).zfill(2)
contract.contract_auto_id = contract_id
contract.contract_name = str(contract_id)+' - '+str(contract.client_short_company) if contract.client_short_company else str(contract.client_short_name)+' '+str(contract.client_short_vorname)
contract.contract_auto_name=str(contract_id)+'_'+str(contract.client_short_company) if contract.client_short_company else str(contract.client_short_name)+' '+str(contract.client_short_vorname)
dsscontracts.tokampagne(contract)
return request.render("website.eingabe-finished",{'contract':contract,'contract_auto_id':contract.contract_auto_id})
@route(['/eingabe/cancel'],type='http', auth='user', website=True, csrf=False)
def cancel_contract(self, **kwargs):
_logger.info("inside: start cancelcontract" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
uuid = kwargs.get('uuid')
contract = request.env['dss.contracts'].search([('uuid','=',uuid)],limit=1)
_logger.info("inside finish_contract: "+str(contract.id)+'--'+str(contract.contract_auto_id)+'--'+str(uuid))
contract.unlink()
return request.render("website.eingabe-finished-delete",{'contract_auto_id':''})
def setcontract(self,contract,kwargs):
projekt_id = kwargs.get('project')
contract.client_short_company = kwargs.get('client_short_company') if kwargs.get('client_short_company') else ''
contract.client_short_vorname = kwargs.get('client_short_vorname') if kwargs.get('client_short_vorname') else ''
contract.client_short_name = kwargs.get('client_short_name') if kwargs.get('client_short_name') else ''
contract.client_short_telefon = kwargs.get('client_short_telefon') if kwargs.get('client_short_telefon') else ''
contract.client_short_email = kwargs.get('client_short_email') if kwargs.get('client_short_email') else ''
contract.client_short_rgemail = kwargs.get('client_short_rgemail') if kwargs.get('client_short_rgemail') else ''
contract.client_short_strasse = kwargs.get('client_short_strasse') if kwargs.get('client_short_strasse') else ''
contract.client_short_plz = kwargs.get('client_short_plz') if kwargs.get('client_short_plz') else ''
contract.client_short_ort = kwargs.get('client_short_ort') if kwargs.get('client_short_ort') else ''
contract.client_short_mobil = kwargs.get('client_short_mobil') if kwargs.get('client_short_mobil') else ''
contract.client_short_website = kwargs.get('client_short_website') if kwargs.get('client_short_website') else ''
contract.runtimesystem = "M"
contract.runtime_m = kwargs.get('contract_time') if kwargs.get('contract_time') else '64'
contract.web_contract_paysum_lz = kwargs.get('web_contract_paysum_lz') if kwargs.get('web_contract_paysum_lz') else 0.0
contract.web_contract_paysum_gfx = kwargs.get('web_contract_paysum_gfx') if kwargs.get('web_contract_paysum_gfx') else 0.0
contract.web_contract_paysum_all = kwargs.get('web_contract_paysum_all') if kwargs.get('web_contract_paysum_all') else 0.0
contract.web_contract_sign_datum = kwargs.get('Datum') if kwargs.get('Datum') else ''
contract.web_contract_sign_ort = kwargs.get('Ort') if kwargs.get('Ort') else ''
contract.contract_date = datetime.datetime.strptime(contract.web_contract_sign_datum, "%d.%m.%Y").date()
contract.web_contract_sign_name = kwargs.get('NameVorname') if kwargs.get('NameVorname') else ''
contract.client_short_BIC = kwargs.get('bic') if kwargs.get('bic') else ''
contract.client_short_IBAN = kwargs.get('iban') if kwargs.get('iban') else ''
contract.web_contract_is_lastschrift = kwargs.get('lastschrift') == 'on' if kwargs.get('lastschrift') else False
contract.work_state_info = kwargs.get('sonder_2') if kwargs.get('sonder_2') else ''
contract.web_contract_kapayment_info = kwargs.get('kapay') if kwargs.get('kapay') else ''
contract.web_contract_alpayment_info = kwargs.get('alpay') if kwargs.get('alpay') else ''
contract.web_contract_sonder_0 = kwargs.get('sonder_0') if kwargs.get('sonder_0') else ''
contract.web_contract_sonder_1 = kwargs.get('sonder_1') if kwargs.get('sonder_1') else ''
contract.web_contract_sonder_2 = kwargs.get('sonder_2') if kwargs.get('sonder_2') else ''
gesamts = kwargs.get('sonder_0') if kwargs.get('sonder_0') else ''
gesamts = gesamts+' //// '+kwargs.get('sonder_1') if kwargs.get('sonder_1') else ''
contract.remark = gesamts
wfields = kwargs.get('werbefeld') if kwargs.get('werbefeld') else ''
wfarray = wfields.split(',') if wfields else []
contract.werbe_feld_selected = [(6, 0, [])]
for wfa in wfarray:
if wfa:
if '_' in wfa:
wfa = wfa.split('_')[1]
wfaid = request.env['dss.advertisefields'].search([('feldname','=',wfa.strip()),('project','=',contract.project.id)],limit=1)
_logger.info("inside update : "+str(projekt_id)+'/'+str(contract.project.id)+'--'+str(wfields)+'--'+str(wfa.strip()+'--'+str(wfaid)))
if wfaid:
contract.werbe_feld_selected = [(4, wfaid.id)]
return contract
@route(['/eingabe/submit_lcdtouch'],type='http', auth='user', website=True, csrf=False)
def submit_lcdtouch(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id)+'--'+str(projectid)+'--'+str(kwargs.get('kamail')))
contract = self.setcontract(request.env['dss.contracts'].search([('id','=',contract_data_id)],limit=1),kwargs)
return request.render("website.eingabe-phase3-upload",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_kfz'],type='http', auth='user', website=True, csrf=False)
def submit_kfz(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
contract_data_id = kwargs.get('contract_data_id')
kd_id = kwargs.get('kd_id')
contract = self.setcontract(request.env['dss.contracts'].search([('id','=',contract_data_id)],limit=1),kwargs)
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase3-upload",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_stream'],type='http', auth='user', website=True, csrf=False)
def submit_stream(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
contract = self.setcontract(request.env['dss.contracts'].search([('id','=',contract_data_id)],limit=1),kwargs)
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase3-upload",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_upload'],type='http', auth='user', website=True, csrf=False)
def submit_upload(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase4-finish",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_finish'],type='http', auth='user', website=True, csrf=False)
def submit_finish(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
submit_finish = kwargs.get('submit')
_logger.info("inside finish : "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id)+'--'+str(submit_finish))
if submit_finish == 'Eingabe beenden':
return request.render("website.eingabe-phase1")
if submit_finish == 'Neuen Vertrag im gleichen Projekt':
return self.changeScreenView(**kwargs)
if submit_finish == 'Neuen Vertrag in anderen Projekt':
return self.ad_portal_my_documents(self, **kwargs)
@route(['/xrechnungin'],type='http', auth='public', website=True, csrf=False)
def Xrechnungask(self, **kwargs):
project = request.env['x_dss.tempkd'].search([('x_guid','=',request.params.get('token'))],limit=1)
if not project:
return request.render("website.xrechnung",{'requestid':request.params.get('token'),'errorstyle':'display:block','contentstyle':'display:none'})
else :
mobile = '' if (not project.x_mobil) or (project.x_mobil == 'False') else project.x_mobil
telefon = '' if (not project.x_telefon) or (project.x_telefon == 'False') else project.x_telefon
email = '' if (not project.x_Email) or (project.x_Email == 'False') else project.x_Email
return request.render("website.xrechnung",{'requestid':request.params.get('token'),'errorstyle':'display:none','contentstyle':'display:block','kdid':project.id,'kdnr':project.x_kdnr,'name':project.x_name,'email':email,'telefon':telefon,'mobil':mobile,'rgemail':project.x_rgemail,'leitweg':project.x_leitwegid})
@route(['/xrechnung/submit'],type='http', auth='public', website=True, csrf=False)
def Xrechnungssubmit(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' -- #'+str(request.httprequest.data)+'#')
kunden_id = kwargs.get('kdid')
client = request.env['x_dss.tempkd'].search([('id','=',kunden_id)],limit=1)
if client:
if client.x_guid == kwargs.get('requestid'):
if client.x_kdnr == kwargs.get('kdnr'):
orgclientt=request.env['x_dss.tempkd'].search([('x_kdnr','=',client.x_kdnr)])
if kwargs.get('rgemail')=='':
orgclientt.write({'x_rgemail': kwargs.get('email')})
else:
orgclientt.write({'x_rgemail': kwargs.get('rgemail')})
orgclientt.write({'x_leitwegid': kwargs.get('leitweg')})
orgclientt.write({'x_finished': True})
# orgclient=request.env['dss.contracts'].search([('contract_auto_id','=',client.x_kdnr)])
# if orgclient:
# if kwargs.get('rgemail')=='':
# orgclient.write({'client_short_rgemail': kwargs.get('email')})
# else:
# orgclient.write({'client_short_rgemail': kwargs.get('rgemail')})
# orgclient.write({'client_short_mobil': kwargs.get('mphone')})
# orgclient.write({'client_short_leitwegid': kwargs.get('leitweg')})
# if orgclient.client_short_email != kwargs.get('email'):
# orgclient.write({'client_short_email': kwargs.get('email')})
# if orgclient.client_short_telefon != kwargs.get('phone'):
# orgclient.write({'client_short_telefon': kwargs.get('phone')})
# if orgclient.client:
# org_contact_client=orgclient.client
# org_contact_client.rgemail = orgclient.client_short_rgemail
# org_contact_client.email = orgclient.client_short_email
# org_contact_client.leitwegid = orgclient.client_short_leitwegid
# org_contact_client.mobil = orgclient.client_short_mobil
# return request.redirect('/danke-xrechnung')
# else :
# errorcode='EF004'
return request.redirect('/danke-xrechnung')
else : errorcode='EF003-'+str(kwargs.get('kdnr'))
else : errorcode='EF002'
else : errorcode='EF001-'+str(kwargs.get('kdid'))
return request.render('website.error-xrechnung',{'error':errorcode})

View File

@ -11,9 +11,9 @@ _logger = logging.getLogger(__name__)
from odoo.tools.json import scriptsafe
class screendesignercontroller(http.Controller):
@http.route('/dss/displaydesigner/', auth='user', website=True, csrf=False)
@http.route('/dss/displaydesigner/undefined', auth='user', website=True, csrf=False)
def changeScreenTemplateView(self):
_logger.info("inside: ")
request.env.ref('DigitalSignage.dss_screenDesigner_action_dss_screenDesigner').run()

View File

@ -0,0 +1,164 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import os
import os.path
import base64
import logging
import werkzeug
import json
from odoo.http import request,Controller, route
from werkzeug.wrappers import Response
_logger = logging.getLogger(__name__)
class WebContractsInput(Controller):
@route(['/eingabe'],type='http', auth='user', website=True, csrf=False)
def web_form(self, **kwargs):
_logger.info("inside: start web_form")
return request.render("website.eingabe-phase1")
@route(['/eingabe/start'],type='http', auth='user', website=True, csrf=False)
def changeScreenView(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
user_id = kwargs.get('websideuserid')
projekt_id = kwargs.get('project')
project = request.env['dss.projects'].search([('id','=',int(projekt_id))],limit=1)
project.reservedkdnr=str(project.reservedkdnr)+';'+str(project.lastkdnr+1)
project.lastkdnr=project.lastkdnr+1
tempid = str(project.projectid) + str(user_id).zfill(2) + str(project.lastkdnr).zfill(2)
tempname = tempid + '_Vertrag'
contract_name = str(tempid)+' - Vertrag ' + str(project.lastkdnr).zfill(2)
contract_id = str(project.projectid) + str(project.lastrealkdnr).zfill(2)
new_contract = request.env['dss.contracts'].create({'project_id':project.projectid,'project':project.id,'client_id':str(project.lastkdnr).zfill(2),'contract_auto_id':str(tempid),'contract_auto_name':str(tempname),'contract_state':39,'contract_name':contract_name})
contract_data_id=new_contract.id
_logger.info("inside: "+str(name)+'--'+str(projekt_id))
return request.render("website."+project.grundsystem_webinput_template,{'websideusername':name,'user_id':str(user_id),'projectid':str(project.projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(str(project.lastrealkdnr).zfill(2)),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_lcdtouch'],type='http', auth='user', website=True, csrf=False)
def submit_lcdtouch(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase3-upload",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_kfz'],type='http', auth='user', website=True, csrf=False)
def submit_kfz(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase3-upload",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_stream'],type='http', auth='user', website=True, csrf=False)
def submit_stream(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase3-upload",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_upload'],type='http', auth='user', website=True, csrf=False)
def submit_upload(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
_logger.info("inside: "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id))
return request.render("website.eingabe-phase4-finish",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
@route(['/eingabe/submit_finish'],type='http', auth='user', website=True, csrf=False)
def submit_finish(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' --'+str(request.httprequest.data))
name = kwargs.get('websideusername')
projekt_id = kwargs.get('project')
projectid = kwargs.get('projectid')
user_id = kwargs.get('user_id')
contract_id = kwargs.get('contract_id')
kd_id = kwargs.get('kd_id')
contract_data_id = kwargs.get('contract_data_id')
submit_finish = kwargs.get('submit')
_logger.info("inside finish : "+str(name)+'--'+str(projekt_id)+'--'+str(kd_id)+'--'+str(contract_id)+'--'+str(contract_data_id)+'--'+str(submit_finish))
if submit_finish == 'Eingabe beenden':
return request.render("website.eingabe-phase1")
if submit_finish == 'Neuen Vertrag im selben Projekt':
return request.render("website.eingabe-phase4-finish",{'websideusername':name,'user_id':str(user_id),'projectid':str(projectid),'project':str(projekt_id),'contract_id':str(contract_id),'kd_id':str(kd_id),'contract_data_id':str(contract_data_id)})
if submit_finish == 'Neuen Vertrag in anderen Projekt':
return request.render("website.eingabe-phase1")
@route(['/xrechnungin'],type='http', auth='public', website=True, csrf=False)
def Xrechnungask(self, **kwargs):
project = request.env['x_dss.tempkd'].search([('x_guid','=',request.params.get('token'))],limit=1)
if not project:
return request.render("website.xrechnung",{'requestid':request.params.get('token'),'errorstyle':'display:block','contentstyle':'display:none'})
else :
mobile = '' if (not project.x_mobil) or (project.x_mobil == 'False') else project.x_mobil
telefon = '' if (not project.x_telefon) or (project.x_telefon == 'False') else project.x_telefon
email = '' if (not project.x_Email) or (project.x_Email == 'False') else project.x_Email
return request.render("website.xrechnung",{'requestid':request.params.get('token'),'errorstyle':'display:none','contentstyle':'display:block','kdid':project.id,'kdnr':project.x_kdnr,'name':project.x_name,'email':email,'telefon':telefon,'mobil':mobile,'rgemail':project.x_rgemail,'leitweg':project.x_leitwegid})
@route(['/xrechnung/submit'],type='http', auth='public', website=True, csrf=False)
def Xrechnungssubmit(self, **kwargs):
_logger.info("inside: start changeScreenTemplateView" + str(request.params)+' --'+str(kwargs)+' -- #'+str(request.httprequest.data)+'#')
kunden_id = kwargs.get('kdid')
client = request.env['x_dss.tempkd'].search([('id','=',kunden_id)],limit=1)
if client:
if client.x_guid == kwargs.get('requestid'):
if client.x_kdnr == kwargs.get('kdnr'):
orgclientt=request.env['x_dss.tempkd'].search([('x_kdnr','=',client.x_kdnr)])
if kwargs.get('rgemail')=='':
orgclientt.write({'x_rgemail': kwargs.get('email')})
else:
orgclientt.write({'x_rgemail': kwargs.get('rgemail')})
orgclientt.write({'x_leitwegid': kwargs.get('leitweg')})
orgclientt.write({'x_finished': True})
# orgclient=request.env['dss.contracts'].search([('contract_auto_id','=',client.x_kdnr)])
# if orgclient:
# if kwargs.get('rgemail')=='':
# orgclient.write({'client_short_rgemail': kwargs.get('email')})
# else:
# orgclient.write({'client_short_rgemail': kwargs.get('rgemail')})
# orgclient.write({'client_short_mobil': kwargs.get('mphone')})
# orgclient.write({'client_short_leitwegid': kwargs.get('leitweg')})
# if orgclient.client_short_email != kwargs.get('email'):
# orgclient.write({'client_short_email': kwargs.get('email')})
# if orgclient.client_short_telefon != kwargs.get('phone'):
# orgclient.write({'client_short_telefon': kwargs.get('phone')})
# if orgclient.client:
# org_contact_client=orgclient.client
# org_contact_client.rgemail = orgclient.client_short_rgemail
# org_contact_client.email = orgclient.client_short_email
# org_contact_client.leitwegid = orgclient.client_short_leitwegid
# org_contact_client.mobil = orgclient.client_short_mobil
# return request.redirect('/danke-xrechnung')
# else :
# errorcode='EF004'
return request.redirect('/danke-xrechnung')
else : errorcode='EF003-'+str(kwargs.get('kdnr'))
else : errorcode='EF002'
else : errorcode='EF001-'+str(kwargs.get('kdid'))
return request.render('website.error-xrechnung',{'error':errorcode})

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="DigitalSignage.model_dss_web_contracts_stream" model="ir.model">
<field name="website_form_key">create_contract.stream</field>
<field name="website_form_access">True</field>
<field name="website_form_label">Alle Streaming Vertragsarten Eingabe</field>
</record>
<record id="DigitalSignage.model_dss_web_contracts" model="ir.model">
<field name="website_form_key">create_contract</field>
<field name="website_form_access">True</field>
@ -27,5 +33,6 @@
'contract_auto_extend_time',
]"/>
</function>
</data>
</odoo>

View File

@ -5,6 +5,7 @@ from . import dss_settings
from . import dss_trigger
from . import dss_ads
from . import dss_contract
from . import dss_contract_uservar
from . import dss_projects
from . import dss_geraetetypen
from . import dss_systemtypen
@ -29,4 +30,11 @@ from . import dss_web_contracts
from . import dss_m2mmail
from . import dsslogger
from . import dss_binaries
from . import dss_linkmail
from . import dss_linkmail
from . import dss_crm_extended
from . import dss_kileads_requests
from . import dss_kileads
from . import dss_res_users
from . import dss_web_contracts_stream
from . import dss_settings_variables

BIN
models/__pycache__/company.cpython-311.pyc Executable file → Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
models/__pycache__/dss_systemtypen.cpython-311.pyc Executable file → Normal file

Binary file not shown.

BIN
models/__pycache__/dsslogger.cpython-311.pyc Executable file → Normal file

Binary file not shown.

Binary file not shown.

View File

@ -21,14 +21,17 @@ class ResCompany(models.Model):
dsspartner_eigenwerbung = fields.Boolean('Eigenwerbekunde ', default=False)
dsspartner_sonstiges = fields.Boolean('Sonstiges', default=False)
dsspartner_sonstiges_text = fields.Char('Sonstiges Text', default=False)
dssprojekte = fields.Many2many('dss.projects', readonly=1 )
dssprojekte = fields.Many2many('dss.projects','kontakt_project_rel','partner_id','project_id',string='Zugewiesene Projekte')
dsspartner_name = fields.Char('Kundenname', default=False)
dsspartner_vorname = fields.Char('KundenVorname', default=False)
dssinternpartner = fields.Boolean('Mitarbeiter', default=False)
dssinternpartner_grafik = fields.Boolean('Grafiker', default=False)
dssinternpartner_technik = fields.Boolean('Techniker', default=False)
dssportaluser = fields.Many2one('res.users', 'Portal User', domain=[('share','=',True)], help='Verknüpfter Portal Benutzer fuer diesen Partner')
# dss_uuid = fields.Char('uuid')
dss_uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
rgemail = fields.Char('Rechnungs-Email', default=False)
leitwegid = fields.Char('Leitweg-ID', default=False)
@api.model
def _default_uuid(self):

View File

@ -198,6 +198,7 @@ class dssmediatypes(models.Model):
maxsize_h = fields.Integer('Maximale Pixel H')
standard_image = fields.Image()
default_filename = fields.Char('Default Dateiname', help='Standard-Dateiname für diesen Mediatyp. Wird automatisch aus dem Dateinamen der hochgeladenen Datei abgerufen')
can_gen_stamp = fields.Boolean('Kann Stempel generieren', help='Darf durch Stempelgenerator gefüllt werden ja/nein')
@api.model
def _default_uuid(self):

335
models/dss_binaries.py Normal file
View File

@ -0,0 +1,335 @@
import ast
import datetime
import json
import re
import uuid
import logging
import base64
import subprocess
import tempfile
import easywebdav
import os
import os.path
import requests
import hashlib
from PIL import Image,ImageDraw,ImageFont
from odoo import api, fields, models, _
from odoo import tools
from odoo.exceptions import ValidationError
from datetime import date
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
from webdav4.client import Client
from webdav4.fsspec import WebdavFileSystem
import sys
TUYA_LOGGER.setLevel(logging.DEBUG)
_logger = logging.getLogger(__name__)
class dssbinaries(models.Model):
@api.model
def create(self,vals):
result = super().create(vals)
return result
_name = "dss.binaries"
_description = "DigitalSignage Dateien"
# _inherit = ['mail.thread','mail.activity.mixin']
_rec_name = "binary_id"
# _inherit = ['mail.thread', 'mail.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date())
date_lastedit = fields.Date('Änderungsdatum')
user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user())
user_lastedit = fields.Char('Änderungsuser')
binary_id = fields.Char(string="Binary ID", required=True, help = "Das ist eine eindeutige ID für diese Dateityp. Sie wird automatisch generiert und sollte nicht manuell geändert werden.", default=lambda self: self._default_binary_id())
binary_name = fields.Char(string="Binary Name", required=True, help = "Der Name des Dateityp, die Sie hochladen möchten. Dieser Name wird in der Benutzeroberfläche angezeigt.")
binary_mediatype = fields.Many2one('dss.mediatypes', string="Binary Mediatype", required=True, help = "Der Mediatyp, der für diese Datei verwendet werden soll. Dies kann z.B. 'Video', 'Bild' oder 'Audio' sein.")
binary_mediatype_can_gen_stamp = fields.Boolean(related='binary_mediatype.can_gen_stamp')
binary_mediatype_name = fields.Char(related='binary_mediatype.medianame', string="Mediatype Name", store=True, help = "Der Name des Mediatyps, der für diese Datei verwendet wird. Dies wird automatisch aus dem Mediatypen-Feld abgerufen")
binary_mediatype_def_filename = fields.Char(related='binary_mediatype.filepartname', string="Mediatype Default Dateiname", help = "Der Standard-Dateiname für diesen Mediatyp. Dies wird automatisch aus dem Mediatypen-Feld abgerufen")
binary_binary = fields.Binary(string="Binary Datei", help = "Die eigentliche Datei, die Sie hochladen möchten. Diese Datei wird in der Datenbank und Cloud gespeichert")
binary_binary_t = fields.Binary(string="Binary Temp Datei", help = "Die eigentliche Datei, die Sie hochladen möchten. Diese Datei wird in der Datenbank und Cloud gespeichert.")
binary_filename = fields.Char(string="Binary Dateiname", help = "Der Name der hochgeladenen Datei. Dies wird automatisch aus dem Dateinamen der hochgeladenen Datei abgerufen.",compute="_compute_binary_filename", store=True)
binary_type = fields.Char(string="Binary Typ", help = "Der Typ den die hochgeladenen Datei haben sollte.")
binary_cloud_link = fields.Char(string="Cloud Link", help = "Der Link zur Datei in der Cloud, wenn die Datei in der Cloud gespeichert ist.")
binary_size = fields.Integer(string="Binary Größe", help = "Die Größe der hochgeladenen Datei in Bytes.")
binary_description = fields.Text(string="Binary Beschreibung", help = "Eine Beschreibung der hochgeladenen Datei. Dies kann Informationen über den Inhalt der Datei, den Verwendungszweck oder andere relevante Details enthalten.")
binary_issaved = fields.Boolean(string="Binary Gespeichert", default=False, help = "Ein Flag, das angibt, ob die Datei in der Datenbank und Cloud gespeichert ist. Wenn dies aktiviert ist, wird die Datei in der Datenbank und Cloud gespeichert.")
binary_secured_ro = fields.Boolean(string="Gesperrt", default=False, help = "Ein Flag, das angibt, ob die Datei gesperrt ist. Wenn dies aktiviert ist, kann die Datei nicht mehr bearbeitet oder gelöscht werden. Sie wird dann auch nicht in Übertragungen oder Ansichten beachtet.")
binary_used_ro = fields.Boolean(string="Genutzt", default=False, help = "Ein Flag, das angibt, ob die Datei in einer Übertragung/Ausstrahlung verwendet wird. Wenn dies aktiviert ist, kann die Datei nicht mehr gelöscht oder überarbeitet werden.")
binary_contract = fields.Many2one('dss.contracts', string="Vertrag", help = "Der Vertrag, zu dem diese Datei gehört. Dies kann verwendet werden, um Dateien zu organisieren und zu verwalten, die mit bestimmten Verträgen verbunden sind.")
@api.depends('binary_binary')
@api.onchange('binary_binary')
def _compute_binary_filename(self):
"""Compute the binary filename based on the uploaded file."""
_logger.info("Binary getting Filename - B_"+str(self.id))
if len(self)>0:
for record in self:
if record.binary_binary:
# Extract the filename from the binary content
extension = 'jpg' # Default extension
if isinstance(self.binary_binary, str):
filedata = base64.b64decode(self.binary_binary.split("base64,")[-1])
else:
filedata = base64.b64decode(self.binary_binary)
filedataStr = str(filedata)
_logger.info("Binary getting Filename - B_"+str(self.id)+" - ["+str(filedataStr[0:23])+"]")
if filedataStr[0:12] == "b'\\x89PNG\\":
extension = 'png'
elif filedataStr[0:17] == "b'\\xff\\xd8\\xff":
extension = 'jpg'
elif filedataStr[0:8] == "b'GIF89a":
extension = 'gif'
elif filedataStr[0:22] == "b'\\x49\\x49\\x2a\\x00":
extension = 'tif'
elif filedataStr[0:27] == "b'\\x25\\x50\\x44\\x46\\x2d":
extension = 'pdf'
elif filedataStr[0:23] == "b'\\x00\\x00\\x00 ftypisom":
extension = 'mp4'
elif filedataStr[0:22] == "b'\\x00\\x00\\x00\\x18ftyp":
extension = 'mp4'
elif filedataStr[0:12] == "b'\\x42\\x4d":
extension = 'bmp'
record.binary_filename = f"{record.binary_mediatype.filepartname}{record.binary_contract.contract_auto_id}.{extension}"
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
@api.model
def _default_create_date(self):
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@api.model
def _default_create_user(self):
return self.env.user.name if self.env.user else 'System'
@api.model
def _default_binary_id(self):
# Generate a unique binary ID based on the current timestamp and a random UUID
return f"Datei_{str(uuid.uuid4())[:8]}"
@api.onchange('binary_binary')
def _onchange_binary_binary(self):
"""Update binary size and type when binary content is changed."""
_logger.info("New Binary B_"+str(self.id))
existing_binary = False
if not self._origin.binary_binary:
existing_binary = False
else:
existing_binary = True
if not self.binary_contract.cloudlink:
raise ValidationError(_("Der Vertrag hat keinen Cloudlink. Bitte überprüfen Sie den Vertrag."))
cloudpath = str(self.binary_contract.cloudlink)
_logger.info("New Binary checking Cloudlink B_"+str(self.id)+" - "+str(cloudpath))
cloudpath = cloudpath + '/' + str(self.binary_mediatype.cloudlink)
client = Client("https://cloud.logumedia.de/remote.php/dav/files/OdooDav/", auth=("odooClient@logumedia.de", "lm2020#OdooDav"))
_logger.info("New Binary checking Cloudlink for cont : "+str(cloudpath))
cloudexists = False
if client.exists(cloudpath):
# Convert self.binary_binary to bytes-like object
if isinstance(self.binary_binary, str):
filedata = base64.b64decode(self.binary_binary.split("base64,")[-1])
else:
filedata = base64.b64decode(self.binary_binary)
filedataStr = str(filedata)
_logger.info("New Binary Cloudlink exists - Saving File - B_"+str(self.id)+" - "+str(cloudpath)+" - " + str(filedata)+' - ' + filedataStr[0:8])
try:
decoded_data = filedata
except base64.binascii.Error as e:
if 'Incorrect padding' in str(e):
filedataStr += b'=' * (4 - len(filedataStr) % 4)
decoded_data = base64.b64decode(filedataStr)
if filedataStr[0:10] == "b'\x89PNG":
extension = 'png'
else:
extension = 'jpg'
_logger.info("New Binary Cloudlink exists - Saving File - B_"+str(self.id)+" - "+str(cloudpath)+" - " + str(base64.b64encode(decoded_data)))
##infile = open('/tmp/'+filename, "w+b")
#infile = tempfile.NamedTemporaryFile(delete=False)
##infile.write(filedata)
##client.upload_fileobj(infile, f"{cloudpath}/{filename}")
##infile.close()
##infile.delete() # Delete the temporary file after upload
cloudexists = True
else:
_logger.info("New Binary Cloudlink does not exists B_"+str(self.id)+" - "+str(cloudpath))
raise ValidationError(_("Der Cloudlink im Vertrag ist nicht vorhanden. Bitte überprüfen Sie den Link ggf. anlegen."))
if cloudexists:
if self.binary_binary:
# Calculate the size of the binary content
self.binary_size = len(filedata)
# Determine the file type based on the binary content
self.binary_cloud_link = f"{cloudpath}/{self.binary_filename}"
self.binary_issaved = True
else:
self.binary_size = 0
self.binary_type = ''
self.binary_cloud_link = ''
self.binary_issaved = False
def dload(self):
"""Download the binary file."""
if not self.binary_binary:
raise ValidationError(_("No binary file to download."))
# Create a temporary file to store the downloaded content
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=self.binary_filename)
temp_file.write(base64.b64decode(self.binary_binary))
temp_file.close()
# Return the file for download
return {
'type': 'ir.actions.act_url',
'url': f'/web/content/{self.id}/{self.binary_filename}?download=true&filename={self.binary_filename}',
'target': 'self',
}
def dedit(self):
"""Edit the binary file."""
return {
'type': 'ir.actions.act_window',
'res_model': 'dss.binaries',
'view_mode': 'form',
'res_id': self.id,
'target': 'new',
}
def resend(self):
"""Resend the binary file to the contract's partner email."""
if not self.binary_contract:
raise ValidationError(_("No contract associated with this binary file."))
if not self.binary_contract.project.standortpartner:
raise ValidationError(_("No partner associated with the contract."))
if not self.binary_contract.project.standortpartner.email:
raise ValidationError(_("The partner does not have an email address."))
# Send email with the binary file as attachment
def genstamp(self):
_logger.info('Create Stamps for Binary: B_'+str(self.id)+' '+str(id))
# Bildparameter definieren
Medium = self.binary_mediatype
if Medium and Medium.can_gen_stamp and self.binary_contract:
_logger.info('Create Stamps for Contract : B_'+str(self.id)+' - Contract: C_'+str(self.binary_contract.id)+'- Medium : M_'+str(Medium.id)+' - '+str(Medium.medianame))
# Bildgröße und Hintergrundfarbe festlegen
background_color = (255, 255, 255) # Weißer Hintergrund (RGB)
# Neues Bild erstellen
maxh = Medium.maxsize_h
maxw = Medium.maxsize_w
image = Image.new("RGB", (maxw, maxh), background_color)
d = ImageDraw.Draw(image)
Zeilen = Medium.maxsize_h // 6
zposy = 2
if self.binary_contract.client:
text = self.binary_contract.contact_company_name
_logger.info('Create Stamps for Contract : B_'+str(self.id)+' - Contract: C_'+str(self.binary_contract.id)+'- Medium : M_'+str(Medium.id)+' - Text1: '+str(text))
if len(text) > 35:
# Trenne den Text an einem Leerzeichen nahe bei Position 40
idx = text.rfind(' ', 0, 35)
if idx == -1:
idx = 35
text2 = text[:idx]
bcount = len(text2) if text2 else 1
fonts = maxw // (bcount ) *1.8
if fonts > maxh:
fonts = maxh - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
d.text((maxw // 2, 1*Zeilen), text2, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = text[idx:]
zposy = 2
if len(text) > 35:
# Trenne den Text an einem Leerzeichen nahe bei Position 40
idx = text.rfind(' ', 0, 35)
if idx == -1:
idx = 35
text2 = text[:idx]
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
d.text((maxw // 2, zposy*Zeilen), text2, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = text[idx:]
zposy = 3
else:
bcount = len(text) if text else 1
fonts = maxw // (bcount ) *1.8
if fonts > maxh:
fonts = maxh - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
d.text((maxw // 2, zposy*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = self.binary_contract.contact_street
bcount = len(text) if text else 1
Zeilen = maxh // 6
fonts = maxw // (bcount ) *1.2
if fonts > maxh:
fonts = maxh - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-Regular.ttf", fonts)
d.text((maxw // 2, 4*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = self.binary_contract.contact_zip+' '+self.binary_contract.contact_city
bcount = len(text) if text else 1
Zeilen = maxh // 6
fonts = maxw // (bcount ) *1.2
if fonts > maxh:
fonts = maxh - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-Regular.ttf", fonts)
d.text((maxw // 2, 5*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
# Bild speichern
filename = Medium.filepartname+self.binary_contract.contract_auto_id+".png"
_logger.info('Create Stamps for Contract : B_'+str(self.id)+' - Contract: C_'+str(self.binary_contract.id)+'- Feld : F_'+str(Medium.id)+' - Filename: '+str(filename))
image.save(filename)
_logger.info("Stamp file created "+str(filename))
_logger.info("Copy file to Binaries B_"+str(self))
try:
self.binary_binary = base64.b64encode(open(filename, "rb").read())
self.binary_filename = filename
self.binary_type = 'image/png'
self.binary_size = os.path.getsize(filename)
self.binary_issaved = False
self.binary_secured_ro = False
self.binary_used_ro = False
finally:
_logger.info("Binary inserted "+str(self))
cloudpath = self.binary_contract.cloudlink
if not cloudpath:
raise ValidationError(_("Der Vertrag hat keinen Cloudlink. Bitte überprüfen Sie den Vertrag."))
if not Medium.cloudlink:
raise ValidationError(_("Der Mediatyp hat keinen Cloudlink. Bitte überprüfen Sie den Mediatyp."))
cloudpath = cloudpath + '/' + str(Medium.cloudlink)
_logger.info("Copy file to Cloud Path : "+str(cloudpath))
try:
client = Client("https://cloud.logumedia.de/remote.php/dav/files/OdooDav/", auth=("odooClient@logumedia.de", "lm2020#OdooDav"))
try:
#client.mkdir(new_folder)
#_logger.info("Make Cloud Path : "+str(new_folder))
client.upload_file(filename, f"{cloudpath}/{filename}")
except Exception as e:
_logger.info("Make Cloud Path error : "+str(e))
finally:
self.binary_issaved = True
_logger.info("File copied to Cloud Path : "+str(cloudpath))
return True

View File

@ -16,6 +16,7 @@ import tempfile
import easywebdav
import os
import os.path
from PIL import Image,ImageDraw,ImageFont
from odoo import api, fields, models, _
@ -38,6 +39,7 @@ TUYA_LOGGER.setLevel(logging.DEBUG)
logging.setLoggerClass(OdooCustomLogger)
_logger = logging.getLogger(__name__)
_logger.setloging(True)
class dsscontracts(models.Model):
@ -65,7 +67,7 @@ class dsscontracts(models.Model):
return ds
def _default_get_ads_last_ad(self):
_logger.info('finding Standard ad '+self.id)
_logger.info('finding Standard ad '+str(self.id))
ds = self.env['dss.ads'].search([('contract','=',self.id),('ad_is_lastpos','=',True)],limit=1)
if not ds:
ds = self.env['dss.ads'].search([('contract','=',self.id)],limit=1)
@ -83,6 +85,8 @@ class dsscontracts(models.Model):
_rec_name = "contract_auto_name"
_inherit = ['mail.thread','dss.activity.mixin','dss.triggermodel']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
contract_creator = fields.Many2one('res.users', string='Vertrag erstellt von', default=lambda self: self.env.user, readonly=True)
contract_create_date = fields.Datetime('Vertrag erstellt am', default=lambda self: fields.Datetime.now(), readonly=True)
cruuid = fields.Char(related='uuid')
contract_id = fields.Char("Kundennummer",store=True,tracking=True)
contract_name = fields.Char('Kurzbezeichnung', required=True,tracking=True)
@ -96,6 +100,8 @@ class dsscontracts(models.Model):
contract_payment_done = fields.Boolean('Zahlungeingang erfolgt',tracking=True)
contract_payment_done_date = fields.Date('Zahlungeingang Datum',tracking=True)
contract_boarding = fields.Boolean('Boarding gebucht?',tracking=True)
contract_grafik = fields.Boolean('Grafik gebucht?',tracking=True)
contract_receipt_done_multi = fields.Boolean('Mehrere Rechnungen nötig ?', tracking=True)
contract_receipt_done = fields.Boolean('Rechnungstellung erfolgt',tracking=True)
@ -103,6 +109,16 @@ class dsscontracts(models.Model):
contract_receipt_done_date = fields.Date('Rechnungsdatum',tracking=True)
contract_receipt_done_until_date = fields.Date('Zahlungsziel', tracking=True)
client_is_inkaso = fields.Boolean('Ist Inkasso eröffnet ?', tracking=True)
client_inkaso_datum = fields.Datetime('Inkasso eröffnet am ', tracking=True)
client_inkaso_info = fields.Char('Inkasso Bemerkungen', tracking=True)
client_is_inkaso_success = fields.Boolean('Ist Inkasso erfolgreich ?', tracking=True)
client_is_anwalt = fields.Boolean('Ist bei Anwalt eröffnet ?', tracking=True)
client_Anwalt_datum = fields.Datetime('Zum Anwalt übergeben am', tracking=True)
client_Anwalt_info = fields.Char('Anwaltlichte Bemerkungen', tracking=True)
client_is_Anwalt_success = fields.Boolean('Ist Anwalt erfolgreich ?', tracking=True)
remark = fields.Html('Bemerkung',tracking=True)
contract_writer = fields.Many2one('res.partner', tracking=True)
@ -115,6 +131,7 @@ class dsscontracts(models.Model):
grafiker = fields.Many2one('res.partner', domain="['&',('dssinternpartner','=',True),('dssinternpartner_grafik','=',True)]", tracking=True, string="abw. Grafiker",help="Grafiker nur wenn abweichend vom Projektgrafiker")
real_grafiker = fields.Char('Grafiker tatsächlich', tracking=True)
techniker = fields.Many2one('res.partner', domain="['&',('dssinternpartner','=',True),('dssinternpartner_technik','=',True)]", tracking=True, string="abw. Techniker (Einspielung)",help="der Techniker der die Einspielung vornehmen kann")
techniker_email = fields.Char(related="techniker.email", string="Techniker Email")
contract_remark = fields.Html('Vertragshinweise',tracking=True)
@ -144,6 +161,8 @@ class dsscontracts(models.Model):
contact_telefon = fields.Char(related="client.phone")
contact_mobil = fields.Char(related="client.mobile")
contact_email = fields.Char(related="client.email")
contact_rgemail = fields.Char(related="client.rgemail")
contact_leitwegid = fields.Char(related="client.leitwegid")
contact_web = fields.Char(related="client.website")
contact_company_name = fields.Char(related="client.company_name")
contact_name = fields.Char(related="client.name")
@ -152,7 +171,7 @@ class dsscontracts(models.Model):
parent_id = fields.Many2one('dss.contracts', string='Parent Task', index=True,tracking=True)
client_short_company = fields.Char('Firmenname Kunde',tracking=True)
client_short_company = fields.Char('Firmenname Kunde',tracking=True)
client_short_vorname = fields.Char('Vorname Kunde',tracking=True)
client_short_name = fields.Char('Name Kunde',tracking=True)
client_short_strasse = fields.Char('Strasse Kunde',tracking=True)
@ -160,9 +179,15 @@ class dsscontracts(models.Model):
client_short_ort = fields.Char('Ort Kunde',tracking=True)
client_short_land = fields.Many2one('res.country','Land Kunde',tracking=True)
client_short_email = fields.Char('Email Kunde',tracking=True)
client_short_rgemail = fields.Char('Rechnungs-Email Kunde',tracking=True)
client_short_telefon = fields.Char('Telefon Kunde',tracking=True)
client_short_mobil = fields.Char('Mobilfunk Kunde',tracking=True)
client_short_website = fields.Char('Webseite Kunde',tracking=True)
client_short_leitwegid = fields.Char('Leitwegid Kunde',tracking=True)
client_short_website = fields.Char('Webseite Kunde',tracking=True)
client_short_leitwegid = fields.Char('Leitwegid Kunde',tracking=True)
client_short_BIC = fields.Char('BIC Kunde',tracking=True)
client_short_IBAN = fields.Char('IBAN Kunde',tracking=True)
client_other_projects = fields.Many2many('dss.projects',string='Weitere Projekte',tracking=True)
@ -179,6 +204,8 @@ class dsscontracts(models.Model):
werbe_feld_selected_btn_pos_w = fields.Integer(related="werbe_feld_selected.btn_pos_w", tracking=True)
werbe_feld_selected_btn_pos_h = fields.Integer(related="werbe_feld_selected.btn_pos_h", tracking=True)
werbe_feld_selected_btn_name = fields.Char(related="werbe_feld_selected.btn_name",tracking=True)
grafik_zuarbeitBis = fields.Date("Grafik Zuarbeit bis", tracking=True)
# need_media = fields.Many2many('dss.mediarelations','mediarelations_contract_rel','contract_id','mediarelations_id',string='benötigte Medien')
last_media = fields.Many2many('dss.mediarelations',string='Medien',domain="[('isreference','=',False)]")
@ -277,8 +304,6 @@ class dsscontracts(models.Model):
info_partner = fields.Many2one('res.partner','Benachrichtigung an : ',tracking=True)
work_marker_1 = fields.Boolean('Markierung 1 aktiv (StartEmail versendet)',tracking=True)
get_marker_1_color_false = fields.Char('Markierung 1 Farbe',compute='_get_marker_1_color_false')
get_marker_1_color_true = fields.Char('Markierung 1 Farbe true',compute='_get_marker_1_color_false')
get_marker_1_color = fields.Char('Markierung 1 Farbe get',compute='_get_marker_1_color_false')
work_marker_2 = fields.Boolean('Markierung 2 aktiv',tracking=True)
get_marker_2_color = fields.Char('Markierung 1 Farbe get',compute='_get_marker_2_color_false')
@ -315,9 +340,21 @@ class dsscontracts(models.Model):
# todo_state_until = fields.Date('Abarbeiten bis',tracking=True)
cloudlink = fields.Char('Cloud Verzeichnis',help='Verzeichnis für den Kunde innerhalb des Projekt Ordners')
web_contract = fields.Many2one('dss.web_contracts' , string='Web_Vertrag', store=True,tracking=True)
web_contract_input_notfinished = fields.Boolean('Web Vertrag Eingabe nicht abgeschlossen',tracking=True)
web_contract_input_finished = fields.Boolean('Web Vertrag Eingabe abgeschlossen',tracking=True)
web_contract_paysum_gfx = fields.Float('Web Vertrag Zahlungssumme Grafik',tracking=True)
web_contract_paysum_lz = fields.Float('Web Vertrag Zahlungssumme Laufzeit',tracking=True)
web_contract_paysum_all = fields.Float('Web Vertrag Zahlungssumme Gesamt',tracking=True)
web_contract_sign_ort = fields.Char('Web Vertrag Ort',tracking=True)
web_contract_sign_datum = fields.Char('Web Vertrag Datum',tracking=True)
web_contract_sign_name = fields.Char('Web Vertrag Unterschrift Name',tracking=True)
web_contract_is_lastschrift = fields.Boolean('Web Vertrag ist Lastschrift',tracking=True)
web_contract_kapayment_info = fields.Char('Web Vertrag Zahlung nach Korrekturabzug Summe',tracking=True)
web_contract_alpayment_info = fields.Char('Web Vertrag Zahlung nach Auslieferung Summe',tracking=True)
web_contract_sonder_0 = fields.Char('Web Vertrag Sonderfeld 01',tracking=True)
web_contract_sonder_1 = fields.Char('Web Vertrag Sonderfeld 02',tracking=True)
web_contract_sonder_2 = fields.Char('Web Vertrag Sonderfeld 03',tracking=True)
tv_reach_PLZ = fields.Char(string='Reichweite PLZ',tracking=True)
ads_radius_PLZ = fields.Integer('Umkreis PLZ in Km',tracking=True)
ads_count_perYear = fields.Selection([('30000','30.000'),('60000','60.000'),('120000','120.000'),('1000000','1.000.000')],'Einblendungen alt',tracking=True)
@ -325,15 +362,21 @@ class dsscontracts(models.Model):
ads_topics = fields.Many2many('dss.contracts_ads_topics', string='Themenliste', tracking=True)
ads_topics_text = fields.Char('Themenliste gesamt',compute='_compute_themenliste')
userdef_vars = fields.Many2many('dss.contracts_uservars', string='Vertrags Uservariablen', tracking=True)
@api.depends('work_marker_1')
@api.onchange('work_marker_1')
def _get_marker_1_color_false(self):
_logger.info('Contract get Marker 1 Color false')
for record in self:
if not record.work_marker_1:
record.get_marker_1_color = dss_settings.dssSettings._get_settingvalue(self,'marker_1_color_unused')
else:
record.get_marker_1_color = dss_settings.dssSettings._get_settingvalue(self,'marker_1_color_used')
try :
_logger.info('Contract get Marker 1 Color false')
self.get_marker_1_color = dss_settings.dssSettings._get_settingvalue(self,'marker_1_color_unused')
for record in self:
if not record.work_marker_1:
record.get_marker_1_color = dss_settings.dssSettings._get_settingvalue(self,'marker_1_color_unused')
else:
record.get_marker_1_color = dss_settings.dssSettings._get_settingvalue(self,'marker_1_color_used')
except :
_logger.info("error")
@api.depends('work_marker_2')
@api.onchange('work_marker_2')
@ -515,7 +558,10 @@ class dsscontracts(models.Model):
if not urlbase:
urlbase = 'https://cloud.logumedia.de/index.php/apps/files/?dir=';
_logger.info("Cloud Open Link Urlbase Used " + str(urlbase))
url=str(urlbase)+str(dss_settings.dssSettings._get_path_converted(self,self.project.cloudlink,self.project))+str(dss_settings.dssSettings._get_path_converted(self,self.cloudlink,self))
if not self.cloudlink:
url=str(urlbase)+str(dss_settings.dssSettings._get_path_converted(self,self.project.cloudlink,self.project))+str(dss_settings.dssSettings._get_path_converted(self,self.cloudlink,self))
else:
url=str(urlbase)+str(dss_settings.dssSettings._get_path_converted(self,self.cloudlink,self))
_logger.info("Cloud Open Link " + str(url))
return {
'type': 'ir.actions.act_url',
@ -670,6 +716,7 @@ class dsscontracts(models.Model):
'phone':self.client_short_telefon,
'mobile':self.client_short_mobil,
'email':self.client_short_email,
'rgemail':self.client_short_rgemail,
'is_company':False})
result.country_id = self.client_short_land
_logger.info('Creating Contact ' + str(result) + ' ' + str(fullname))
@ -1034,6 +1081,25 @@ class dsscontracts(models.Model):
if self.contract_auto_id == "":
self.contract_auto_id = cidstr
def pyopen_dss_contract_add_uservar(self):
_logger.info('Open Add Uservar Form')
view = self.env.ref("DigitalSignage.dss_uservar_form")
uservar=self.env['dss.contracts_uservars'].create({'contract':self.id})
self.userdef_vars = [(4, uservar.id)]
return {
'type': 'ir.actions.act_window',
'view_mode': 'form' ,
'view_type': 'form' ,
'view_id': view.id,
'res_model': 'dss.contracts_uservars' ,
'target': 'new' ,
'display_name' : 'Neu Uservariable einfügen',
'views':[(view.id,'form')],
'res_id':uservar.id,
'context': {'default_contract':self.id},
}
@api.depends('shortwerbe_feld_selected')
@api.onchange('werbe_feld_selected')
def _compute_cutshort(self):
@ -1094,7 +1160,8 @@ class dsscontracts(models.Model):
self.cloudlink = str(projectcloudpath)+str(dss_settings.dssSettings.getClientpath(self,self))
else:
self.cloudlink = str(dss_settings.dssSettings.getprojectpath(self,self.project))+str(dss_settings.dssSettings.getClientpath(self,self))
action = (self.env["confirmation.wizard"].confirm_message(_("Ist die Bezeichnung des neuen Kunden : "+self.contract_auto_name+" richtig ?( "+str(self.cloudlink)+" ) (Cloudornder wird entsprechend angelegt) !"),title="Bitte bestätigen",method="createcontract",records=self,callback_params={"template":self.id})
cl = str(self.cloudlink)
action = (self.env["confirmation.wizard"].confirm_message(_("Ist die Bezeichnung des neuen Kunden : "+self.contract_auto_name+" richtig ?( "+str(cl)+" ) (Cloudornder wird entsprechend angelegt) !"),title="Bitte bestätigen",method="createcontract",records=self,callback_params={"template":self.id})
)
if action:
return action
@ -1108,8 +1175,8 @@ class dsscontracts(models.Model):
#client.mkdir(new_folder)
#_logger.info("Make Cloud Path : "+str(new_folder))
_logger.info("Create Standard Cloud Structure for Client "+str(newClient.id)+" - "+str(newClient.cloudlink))
client.copy(newClient.project_grundsystem_typ_cloud_contract_template+'/',cloudpath)
_logger.info("Make Standard Cloud Path : "+str(cloudpath+'/'+str(newClient.project_grundsystem_typ_cloud_contract_template)))
client.copy(str(newClient.project_grundsystem_typ_cloud_contract_template)+'/',cloudpath)
_logger.info("Make Standard Cloud Path : "+str(cloudpath)+'/'+str(newClient.project_grundsystem_typ_cloud_contract_template))
except Exception as e:
_logger.info("Make Cloud Path error : "+str(e))
return True
@ -1184,6 +1251,8 @@ class dsscontracts(models.Model):
self.client.phone = self.client_short_telefon
self.client.mobile = self.client_short_mobil
self.client.email = self.client_short_email
self.client.rgemail = self.client_short_rgemail
self.client.leitwegid = self.client_short_leitwegid
def pyaction_dss_contract_update_short_from_partner(self):
self.client_short_company=self.client.company_name
@ -1195,6 +1264,8 @@ class dsscontracts(models.Model):
self.client_short_telefon=self.client.phone
self.client_short_mobil=self.client.mobile
self.client_short_email=self.client.email
self.client_short_rgemail=self.client.rgemail
self.client_short_leitwegid=self.client.leitwegid
def buildText(self):
@ -1410,3 +1481,90 @@ class dsscontracts(models.Model):
else:
return attachment
def get_attachments_by_mediatype_id(self, mediatypeid):
_logger.info('Get Attachments for Contract : C_'+str(self.id)+' - Mediatype : '+str(mediatypeid))
attachment = self.env['dss.binaries'].search([('binary_contract', '=', self.id), ('binary_mediatype', '=', mediatypeid)])
if not attachment:
_logger.info('No Attachments found for Contract : C_'+str(self.id)+' - Mediatype : '+str(mediatypeid))
return ""
else:
return attachment
@api.model
def pyaction_create_stamps(self):
_logger.info('Create Stamps for Contract : C_'+str(self.id))
# Bildparameter definieren
for feld in self.werbe_feld_selected:
_logger.info('Create Stamps for Contract : C_'+str(self.id)+' - Feld : F_'+str(feld.id)+' - '+str(feld.feldname))
# Bildgröße und Hintergrundfarbe festlegen
background_color = (255, 255, 255) # Weißer Hintergrund (RGB)
# Neues Bild erstellen
image = Image.new("RGB", (feld.btn_pos_w, feld.btn_pos_h), background_color)
d = ImageDraw.Draw(image)
Zeilen = feld.btn_pos_h // 6
zposy = 2
if self.client:
text = self.contact_company_name
if len(text) > 35:
# Trenne den Text an einem Leerzeichen nahe bei Position 40
idx = text.rfind(' ', 0, 35)
if idx == -1:
idx = 35
text2 = text[:idx]
bcount = len(text2) if text2 else 1
fonts = feld.btn_pos_w // (bcount ) *1.8
if fonts > feld.btn_pos_h:
fonts = feld.btn_pos_h - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
d.text((feld.btn_pos_w // 2, 1*Zeilen), text2, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text1 = text[idx:]
zposy = 2
if len(text1) > 35:
# Trenne den Text an einem Leerzeichen nahe bei Position 40
idx = text1.rfind(' ', 0, 35)
if idx == -1:
idx = 35
text2 = text1[:idx]
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
d.text((feld.btn_pos_w // 2, zposy*Zeilen), text2, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = text1[idx:]
zposy = 3
else:
bcount = len(text) if text else 1
fonts = feld.btn_pos_w // (bcount ) *1.8
if fonts > feld.btn_pos_h:
fonts = feld.btn_pos_h - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-SemiBold.ttf", fonts)
d.text((feld.btn_pos_w // 2, zposy*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = self.contact_street
bcount = len(text) if text else 1
Zeilen = feld.btn_pos_h // 6
fonts = feld.btn_pos_w // (bcount ) *1.2
if fonts > feld.btn_pos_h:
fonts = feld.btn_pos_h - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-Regular.ttf", fonts)
d.text((feld.btn_pos_w // 2, 4*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
text = self.contact_zip+' '+self.contact_city
bcount = len(text) if text else 1
Zeilen = feld.btn_pos_h // 6
fonts = feld.btn_pos_w // (bcount ) *1.2
if fonts > feld.btn_pos_h:
fonts = feld.btn_pos_h - 10
if fonts <=0 :
fonts = 10
# font = ImageFont.truetype("addons/web/static/fonts/sign/Zeyada-Regular.ttf", fonts)
font = ImageFont.truetype("addons/web/static/fonts/google/Open_Sans/Open_Sans-Regular.ttf", fonts)
d.text((feld.btn_pos_w // 2, 5*Zeilen), text, fill="black",align="center", anchor="ms", font=font) # Beispiel: Ein Rechteck
# Bild speichern
image.save(self.contract_auto_id+"_"+feld.feldname+".png")

View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*
# Test
# Test2
import ast
import datetime
import json
import re
import uuid
from .dsslogger import OdooCustomLogger
import logging
import base64
import subprocess
import tempfile
import easywebdav
import os
import os.path
from PIL import Image,ImageDraw,ImageFont
from odoo import api, fields, models, _
from odoo import tools
from . import dss_settings
from . import dss_ads
from odoo.exceptions import ValidationError
from odoo.exceptions import UserError
from datetime import date
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
from webdav4.client import Client
from webdav4.fsspec import WebdavFileSystem
import sys
TUYA_LOGGER.setLevel(logging.DEBUG)
logging.setLoggerClass(OdooCustomLogger)
_logger = logging.getLogger(__name__)
class dsscontractuservars(models.Model):
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
_name = "dss.contracts_uservars"
_description = "DigitalSignage Vertraeg Uservariablen"
_rec_name = "uuid"
_inherit = ['mail.thread','dss.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
var_name = fields.Char(string="Variable Name", tracking=True)
var_value = fields.Char(string="Variable Wert", tracking=True)
var_description = fields.Text(string="Variable Beschreibung",tracking=True)
contract = fields.Many2one('dss.contracts', string="Vertrag",required=True, tracking=True)

View File

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class ResCRMExtended(models.Model):
_inherit = 'crm.lead'
fromKI = fields.Boolean(string='Import from KI', default=False, readonly=True)

110
models/dss_kileads.py Normal file
View File

@ -0,0 +1,110 @@
import ast
import datetime
import uuid
import logging
from PIL import Image,ImageDraw,ImageFont
from odoo import api, fields, models, _
from odoo import tools
from odoo.exceptions import ValidationError
from datetime import date
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
from webdav4.client import Client
from webdav4.fsspec import WebdavFileSystem
import sys
TUYA_LOGGER.setLevel(logging.DEBUG)
_logger = logging.getLogger(__name__)
class dsskileadscategories(models.Model):
_name = "dss.kileads.categories"
_description = "DigitalSignage KI Lead Kategorien"
_rec_name = "uuid"
# _inherit = ['mail.thread', 'mail.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date())
date_lastedit = fields.Date('Änderungsdatum')
user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user())
user_lastedit = fields.Char('Änderungsuser')
categorie = fields.Char(string="Kategorie", required=True)
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
@api.model
def _default_create_date(self):
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@api.model
def _default_create_user(self):
return self.env.user.name if self.env.user else 'System'
class dsskileads(models.Model):
_name = "dss.kileads"
_description = "DigitalSignage KI Leads"
_inherit = ['mail.thread','mail.activity.mixin']
_rec_name = "uuid"
# _inherit = ['mail.thread', 'mail.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date())
date_lastedit = fields.Date('Änderungsdatum')
user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user())
user_lastedit = fields.Char('Änderungsuser')
lead_request = fields.Many2one('dss.kileads.requests', string="Anfrage des Leads",tracking=True)
lead_id = fields.Char(string="Lead ID", required=True, tracking=True)
lead_request_id = fields.Char(related="lead_request.request_id")
lead_converted = fields.Boolean(string='Lead ausgewertet',tracking=True)
lead_raw_data = fields.Char(string="Raw Antwort der Anfrage")
#lead_crm_lead = fields.Many2one("crm.leads")
lead_nummer = fields.Integer(string="Nummer im Request")
lead_name = fields.Char(string="Name",tracking=True)
lead_address = fields.Char(string="Adresse",tracking=True)
lead_address_city = fields.Char(string="Adresse Stadt",tracking=True)
lead_address_street = fields.Char(string="Adresse Strasse",tracking=True)
lead_address_country = fields.Char(string="Adresse Land",tracking=True)
lead_address_district = fields.Char(string="Adresse Bezirk",tracking=True)
lead_address_state = fields.Char(string="Adresse Bundenland",tracking=True)
lead_address_zip = fields.Char(string="Adresse PLZ",tracking=True)
lead_google_id = fields.Char(string="Google ID",tracking=True)
lead_place_id = fields.Char(string="Google Place ID",tracking=True)
lead_main_category = fields.Char(string="Tätigkeitsfeld",tracking=True)
#lead_categories = fields.Many2many("dss.kileads.categories",string="Kategorien")
lead_phone = fields.Char(string="Telefon",tracking=True)
lead_website = fields.Char(string="Webseite",tracking=True)
lead_latitude = fields.Char(string="Latitude",tracking=True)
lead_longitude = fields.Char(string="Longitude",tracking=True)
lead_picture_url = fields.Char(string="Bild",tracking=True)
lead_exported_ignore_caller = fields.Boolean(string="vom Caller zu ignorieren",tracking=True)
lead_exported_to_caller = fields.Boolean(string="zum Caller exportiert",tracking=True)
lead_caller_response = fields.Char(string="Antwort vom Caller",tracking=True)
lead_used_in_crm = fields.Boolean(string="In CRM verwendet",tracking=True)
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
@api.model
def _default_create_date(self):
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@api.model
def _default_create_user(self):
return self.env.user.name if self.env.user else 'System'
@api.model
def exportcallercsv(self):
for record in self:
record.lead_exported_to_caller = True

View File

@ -0,0 +1,177 @@
import ast
import datetime
import json
import re
import uuid
import logging
import base64
import subprocess
import tempfile
import easywebdav
import os
import os.path
import requests
import hashlib
from PIL import Image,ImageDraw,ImageFont
from odoo import api, fields, models, _
from odoo import tools
from odoo.exceptions import ValidationError
from datetime import date
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
from webdav4.client import Client
from webdav4.fsspec import WebdavFileSystem
import sys
from urllib.parse import urlencode
TUYA_LOGGER.setLevel(logging.DEBUG)
_logger = logging.getLogger(__name__)
class dsskileadsrequests(models.Model):
@api.model
def create(self,vals):
result = super().create(vals)
return result
_name = "dss.kileads.requests"
_description = "DigitalSignage KI Lead requests"
_inherit = ['mail.thread','mail.activity.mixin']
_rec_name = "request_id"
# _inherit = ['mail.thread', 'mail.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date())
date_lastedit = fields.Date('Änderungsdatum')
user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user())
user_lastedit = fields.Char('Änderungsuser')
request_id = fields.Char(string="Request ID", required=True, default=lambda self: self._default_request_id(),tracking=True)
request_name = fields.Char(string="Name der Anfrage",tracking=True)
request_isparent = fields.Boolean(string="Hauptanfrage",tracking=True)
request_data_count = fields.Integer(string="Anfrage Anzahl",tracking=True)
request_data_offset = fields.Integer(string="Beginn der Anfrage",tracking=True)
request_parent = fields.Many2one("dss.kileads.requests")
request_text = fields.Char(string="Anforderungs-Text", required=True, help = "Der Text der Anfrage die zu den Ergebnissen geführt hat.",tracking=True)
request_project = fields.Many2one('dss.projects', string="Anfrage für Projekt",tracking=True)
request_finished = fields.Boolean(string='Anfrage Abgeschlossen',tracking=True)
request_translated = fields.Boolean(string='Anfrage Übersetzt',tracking=True)
request_canhavemore = fields.Boolean(string='Anfrage kann mehr Daten haben',tracking=True)
request_results = fields.Many2many('dss.kileads', string="Leads",tracking=True)
request_raw = fields.Char(string="Raw Antwort der Anfrage")
aktcount = fields.Integer(string="akt. Anzahl")
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
@api.model
def _default_create_date(self):
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
@api.model
def _default_create_user(self):
return self.env.user.name if self.env.user else 'System'
@api.model
def _default_request_id(self):
# Generate a unique binary ID based on the current timestamp and a random UUID
return f"Request_{str(uuid.uuid4())[:8]}"
def pyaction_dss_kileads_requests_dorequest(self):
import http.client
conn = http.client.HTTPSConnection("google-maps-extractor2.p.rapidapi.com")
headers = {
'x-rapidapi-key': "e4644aea12mshd78789f07136e6dp15fc91jsned56df96c261",
'x-rapidapi-host': "google-maps-extractor2.p.rapidapi.com"
}
query_params = {
"query": self.request_text,
"offset": str(self.request_data_offset),
"limit": str(self.request_data_count),
"zoom": "15",
"country": "de",
"language": "de"
}
url = "/locate_and_search?" + urlencode(query_params)
conn.request("GET", url, headers=headers)
res = conn.getresponse()
data = res.read()
self.request_raw = data
self.request_finished = True
self.request_translated = False
return True
def pyaction_dss_kileads_requests_dobuild(self):
if not self.request_raw:
raise ValidationError("Keine Daten zum Erzeugen vorhanden ! Abfrage ausführen ...")
try:
raw_data = json.loads(self.request_raw)
except json.JSONDecodeError:
raise ValidationError("Invalid JSON format in raw data.")
results = []
counter = self.aktcount
icounter = 0
for item in raw_data.get("data", []):
kilead = self.env['dss.kileads'].create({"lead_name": item.get("name"),"lead_id": self.request_id + "_" + str(counter)})
kilead.lead_address = item.get("address")
kilead.lead_phone = item.get("full_phone")
kilead.lead_google_id = item.get("google_id")
kilead.lead_place_id = item.get("place_id")
kilead.lead_main_category = item.get("main_category")
kilead.lead_website = item.get("website_url")
kilead.lead_picture_url = item.get("featured_photo")
kilead.lead_longitude = item.get("longitude" )
kilead.lead_latitude = item.get("latitude")
kilead.lead_address_city = item.get("detailed_address").get("city")
kilead.lead_address_street = item.get("detailed_address").get("street")
kilead.lead_address_zip = item.get("detailed_address").get("zip_code")
kilead.lead_address_country = item.get("detailed_address").get("country")
kilead.lead_address_state = item.get("detailed_address").get("state")
kilead.lead_address_district = item.get("detailed_address").get("district")
kilead.lead_nummer = counter
kilead.lead_converted = True
kilead.lead_request = self
counter += 1
icounter += 1
self.aktcount = counter
kilead.lead_raw_data = item
self.request_results = [(4,kilead.id)]
self.request_canhavemore = True
if icounter<self.request_data_count:
self.request_finished = True
self.request_canhavemore = False
self.request_translated = True
return True
def pyaction_dss_kileads_requests_nextbuild(self):
if not self.request_canhavemore:
raise ValidationError("Anfrage kann keine weiteren Daten enthalten !")
newrequest = self.env['dss.kileads.requests'].create({
"request_name": self.request_name + " - Folgeanfrage ab " + str(self.request_data_offset + self.request_data_count),
"request_isparent": False,
"request_data_count": self.request_data_count,
"request_data_offset": self.request_data_offset + self.request_data_count,
"request_parent": self.id,
"request_text": self.request_text,
"request_project": self.request_project.id
})
return True

33
models/dss_linkmail.py Executable file
View File

@ -0,0 +1,33 @@
import uuid
from .dsslogger import OdooCustomLogger
import logging
import datetime
from odoo import api, fields, models, _
from odoo import tools
logging.setLoggerClass(OdooCustomLogger)
_logger = logging.getLogger(__name__)
class dsslinkmail(models.Model):
@api.model
def analyze_emails(self):
self.analyzed = True
_name = "dss.linkmail"
_description = "DigitalSignage TV Link Rückmeldungen"
# _rec_name = "statusname"
_inherit = ['mail.thread', 'mail.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
date_create = fields.Datetime('Erstellungsdatum',default=lambda self: self._default_create_date())
date_lastedit = fields.Datetime('Änderungsdatum')
analyzed = fields.Boolean('Analysiert', default=False, tracking=True)
level = fields.Char('Schwellengrenze',tracking=True)
@api.model
def _default_create_date(self):
return datetime.datetime.now()
# ... andere Methoden ...
@api.model
def _default_uuid(self):
return str(uuid.uuid4())

View File

@ -37,7 +37,7 @@ TUYA_LOGGER.setLevel(logging.DEBUG)
logging.setLoggerClass(OdooCustomLogger)
_logger = logging.getLogger(__name__)
_logger.setloging(False)
class dssprojects(models.Model):
@ -74,8 +74,11 @@ class dssprojects(models.Model):
grundsystem_default_cloud_structure_contract = fields.Char(related='grundsystemname.default_cloud_structure_contract')
grundsystem_showonlinestate = fields.Boolean(related='grundsystemname.showonlinestate')
grundsystem_showonlinestate_type = fields.Selection(related='grundsystemname.showonlinestate_type')
grundsystem_inputform_type = fields.Char(related='grundsystemname.inputform_type',tracking=True)
grundsystemicon_different = fields.Boolean('Grundsystem Icon anders',default=False,tracking=True)
grundsystemicon_different_image = fields.Binary('Anderes Icon',tracking=True)
grundsystem_webinput_template = fields.Char(related='grundsystemname.web_input_template',tracking=True)
btntemplate = fields.Many2one('dss.display.templates',string='Buttonsvorlage',tracking=True)
btntemplate_displaytemplate_fullsize_w = fields.Integer(related='btntemplate.fullsize_w',string="Auflösung Breite",tracking=True)
@ -162,6 +165,12 @@ class dssprojects(models.Model):
playsetup_user = fields.Many2one('res.users',domain="[('user_type','=','1')]",string='Einspielung - Benutzer',tracking=True)
lastkdnr = fields.Integer('Letzte Temp. KdNr', tracking=True)
lastrealkdnr = fields.Integer('Letzte Real. KdNr', tracking=True)
reservedkdnr = fields.Char('Reservierte KdNr', tracking=True)
web_input_template = fields.Char('Web-Eingabe Template', tracking=True)
@api.model
def _read_group_system_ids(self, stages, domain, order):
project_system_ids = self.env['dss.systemtypen'].search([('open_close_standard_state','=',False)], order='order')

18
models/dss_res_users.py Executable file
View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
import uuid
import logging
from odoo import api,fields, models
_logger = logging.getLogger(__name__)
class Resusers(models.Model):
_name = "res.users"
_inherit = "res.users"
# company_type = fields.Selection(selection_add=[('dss_client','Werbekunde'),('dss_partner','Partnerunternehmen')])
dss_projects = fields.Many2many('dss.projects',string='DigitalSignage Projekte')
# dss_uuid = fields.Char('uuid')

View File

@ -87,6 +87,8 @@ class dssSettings(models.Model):
showdebug = fields.Boolean('Debug',help='Debug Informationen aktivieren ',tracking=True)
m2mcron = fields.Many2one('ir.cron',string='M2M Cron',tracking=True)
variables = fields.Many2many('dss.settings.vars',string='Einstellungs Variablen',tracking=True)
def _get_settingvalue(self,valuename):
settings = (self.env['dss.settings'].search([],limit=1))
wert = settings._origin.read([valuename])[0][valuename]

View File

@ -0,0 +1,44 @@
import ast
import datetime
import json
import re
import uuid
import logging
import base64
import subprocess
import tempfile
import easywebdav
import os
import os.path
from odoo import api, fields, models, _
from odoo import tools
from odoo.exceptions import ValidationError
from datetime import date
from datetime import datetime
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
import sys
TUYA_LOGGER.setLevel(logging.DEBUG)
_logger = logging.getLogger(__name__)
class dssSettingVars(models.Model):
_name = "dss.settings.vars"
_description = "DigitalSignage Einstellungs Variablen"
_inherit = ['mail.thread','mail.activity.mixin']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
varname = fields.Char('VariablenName',tracking=True)
vargroup = fields.Char('VariablenGruppe',tracking=True)
varvalue = fields.Char('VariablenWert',tracking=True)
vardescription = fields.Text('VariablenBeschreibung',tracking=True)
@api.model
def _default_uuid(self):
return str(uuid.uuid4())

View File

@ -53,6 +53,8 @@ class dsssystemtypen(models.Model):
order = fields.Integer('Reihenfolge')
showonlinestate = fields.Boolean('OnlineStatus zeigen')
showonlinestate_type = fields.Selection([('RPORT','RPort Status'),('VNNOX','Vnnox System')])
inputform_type = fields.Char('Eingabeformular Typ', tracking=True)
web_input_template = fields.Char('Web-Eingabe Template', tracking=True)

View File

@ -13,12 +13,14 @@ from dateutil.relativedelta import relativedelta
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
import sys
import requests
import json
TUYA_LOGGER.setLevel(logging.DEBUG)
TUYA_LOGGER.setLevel(logging.ERROR)
logging.setLoggerClass(OdooCustomLogger)
_logger = logging.getLogger(__name__)
#_logger.setloging(False)
##_logger = logging.getLogger(__name__)
@ -33,10 +35,297 @@ class trigger(models.Model):
_logger.info("GetValue called for "+str(Table)+" Fieldname "+str(FieldName)+' -> '+str(self)+' / '+str(Dataset))
Field=self.env['ir.model.fields'].search([('id','=',FieldName)])
_logger.info("GetValue called for "+str(Table)+" Fieldname "+str(Field))
_logger.info("GetValue called for "+str(Table)+" Fieldname "+str(Field)+' -> '+str(Dataset[Field.name]))
return Dataset[Field.name]
_logger.info("GetValue called for "+str(Table)+" Fieldname "+str(Field)+' -> '+str(Dataset[Field.name])+' / '+str(Field.ttype))
if (str(Field.ttype) == "many2one"):
resStr = str(Dataset[Field.name].id)
elif (str(Field.ttype) == "date"):
resStr = Dataset[Field.name]
elif (str(Field.ttype) == "boolean"):
resStr = bool(Dataset[Field.name])
elif (str(Field.ttype) == "int"):
resStr = Dataset[Field.name]
else:
resStr = str(Dataset[Field.name])
_logger.info("GetValue called for "+str(Table)+" Fieldname "+str(Field)+' Value : '+str(resStr))
return resStr
@api.model
def GetValueData(self,Dataset,Fieldname):
_logger.info("GetValueData called for Fieldname "+str(Fieldname)+' -> '+str(self)+' / '+str(Dataset))
Field=self.env['ir.model.fields'].search([('id','=',Fieldname)])
_logger.info("GetValueData called for Fieldname "+str(Field))
_logger.info("GetValueData called for Fieldname "+str(Field)+' -> '+str(Dataset[Field.name])+' / '+str(Field.ttype))
if (str(Field.ttype) == "many2one"):
resStr = str(Dataset[Field.name].id)
elif (str(Field.ttype) == "date"):
resStr = Dataset[Field.name]
elif (str(Field.ttype) == "boolean"):
resStr = bool(Dataset[Field.name])
elif (str(Field.ttype) == "integer"):
resStr = int(Dataset[Field.name])
elif (str(Field.ttype) == "int"):
resStr = int(Dataset[Field.name])
else:
resStr = str(Dataset[Field.name])
_logger.info("GetValue called for Fieldname "+str(Field)+' Value : '+str(resStr))
return resStr
@api.model
def SetUserVar(self,varname,varvalue,descriotion="",Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
contract = None
if 'contract' in Dataset._fields:
contract = Dataset.contract
if not contract:
_logger.error('Trigger Aktion TRA_' + str(self)+' SetUserVar - Kein Vertrag gefunden für Dataset : '+str(Dataset))
return False
uservar = self.env['dss.contracts_uservars'].search([('contracts_varid','=',varname),('contract','=',contract.id)])
if not uservar:
uservar = self.env['dss.contracts_uservars'].create({
'contracts_varid': varname,
'var_name': varname,
'var_value': varvalue,
'var_description': descriotion,
'contract': contract.id
})
_logger.info('Trigger Aktion TRA_' + str(self)+' SetUserVar - Neue Variable erstellt : '+str(varname)+' = '+str(varvalue)+' für Vertrag : '+str(contract))
else:
uservar.var_value = varvalue
uservar.var_description = descriotion
_logger.info('Trigger Aktion TRA_' + str(self)+' SetUserVar - Variable aktualisiert : '+str(varname)+' = '+str(varvalue)+' für Vertrag : '+str(contract))
return True
@api.model
def SetData(self,Table,FieldName,NewValue,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
_logger.info("SetData called for "+str(Table)+" Fieldname "+str(FieldName)+' NewValue '+str(NewValue)+' -> '+str(self)+' / '+str(Dataset))
Field=self.env['ir.model.fields'].search([('id','=',FieldName)])
_logger.info("SetData called for "+str(Table)+" Fieldname "+str(Field))
Dataset[Field.name] = NewValue
return True
@api.model
def GetUserVar(self,varname,stdvalue,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
contract = None
if 'contract' in Dataset._fields:
contract = Dataset.contract
if not contract:
_logger.error('Trigger Aktion TRA_' + str(self)+' GetUserVar - Kein Vertrag gefunden für Dataset : '+str(Dataset))
return stdvalue
uservar = self.env['dss.contracts_uservars'].search([('var_name','=',varname),('contract','=',contract.id)])
if not uservar:
_logger.error('Trigger Aktion TRA_' + str(self)+' GetUserVar - Variable nicht gefunden : '+str(varname)+' für Vertrag : '+str(contract))
return stdvalue
_logger.info('Trigger Aktion TRA_' + str(self)+' GetUserVar - Variable gefunden : '+str(varname)+' = '+str(uservar.var_value)+' für Vertrag : '+str(contract))
return uservar.var_value
@api.model
def AddDate(self,mydate,days):
_logger.debug("AddDate called for "+str(mydate)+" Adddate "+str(days))
newdate = mydate + relativedelta(days=int(days))
_logger.info("AddDate called for "+str(mydate)+" Adddate "+str(days)+" = "+str(newdate))
return newdate
@api.model
def MakeNotiz(self,Title,Text,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
if (not Text): Text =''
body = Text + '('+str(Dataset.id)+')'
Dataset.message_post(body=body,author_id=self.env.ref('base.partner_root').id,subject=Title)
_logger.info('Trigger Aktion TRA_' + str(self)+' Create notice '+str(Title)+' + Text : '+str(body))
return True
@api.model
def PostChannel(self,Info_Subject,BotText,postChannel,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
if (not BotText): BotText=''
body = BotText + '('+str(Dataset.id)+')'
Channel = self.env["mail.channel"].browse(int(postChannel))
Channel.message_post(body=body,author_id=self.env.ref('base.partner_root').id,subject=Info_Subject,message_type="comment",subtype_xmlid="mail.mt_comment")
return True
@api.model
def MakeTask(self,Info_Subject,Activity_text,deadline,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
self.env['mail.activity'].create({
'display_name': Info_Subject,
'summary': Activity_text,
'date_deadline': deadline,
'user_id': self.activity_user.id,
'res_id': Dataset.id,
'res_model_id': Dataset._get_model_id(),
'activity_type_id': self.activity_type.id
})
return True
@api.model
def SetMarker(self,Markerid,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
Dataset.marker_list = [(4,int(Markerid))]
return True
@api.model
def LogEntry(self,Name,Text):
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
if (not Text): Text =''
_logger.info('LOG Entry : '+str(Text)+' ('+str(Name)+')')
return True
@api.model
def WebLog(self,Text):
DebugText = self.env['ir.config_parameter'].sudo().get_param('dss.global.debugout')
if (not Text): Text =''
if (not DebugText): DebugText = ''
neuDebugText = DebugText + Text + '\n'
self.env['ir.config_parameter'].sudo().set_param('dss.global.debugout',neuDebugText)
return True
def Month(self,DateValue):
if (not DateValue): Exception('Kein Datum angegeben !')
if (isinstance(DateValue, str)):
DateValue = datetime.strptime(DateValue, '%Y-%m-%d').date().month
if (isinstance(DateValue, datetime)):
DateValue = DateValue.month
if (isinstance(DateValue, date)):
DateValue = DateValue.month
return DateValue
@api.model
def CheckMarker(self,Markername,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
if Dataset.marker_list:
for mark in Dataset.marker_list:
if str(mark.id) == str(Markername):
_logger.info('Trigger Check Marker '+str(Markername)+' found in '+str(mark.markername))
return True
return False
@api.model
def CheckChange(self,TriggerTable,FieldName,ChangeList):
Field=self.env['ir.model.fields'].search([('id','=',FieldName)])
_logger.info("CheckChange called for "+str(TriggerTable)+" Fieldid "+str(FieldName)+" Fieldname "+str(Field.name)+' ChangeList : '+str(ChangeList))
if (str(Field.name) in ChangeList):
_logger.info("CheckChange called for "+str(TriggerTable)+" Fieldid "+str(FieldName)+" Fieldname "+str(Field.name)+' ChangeList : '+str(ChangeList)+' = TRUE')
return True
return False
@api.model
def getAllDataset(self,Table,Domain):
_logger.info("getAllDataset called for "+str(Table)+" Domain "+str(Domain))
tablename = self.env['ir.model'].search([('id','=',Table)]).model
if (not Domain) or (Domain == '') or (Domain == 'False') or (Domain == 'None') or (Domain == '0') or (Domain == 'null'):
_logger.info("getAllDataset called for "+str(tablename)+" ALL DATA")
Dataset = self.env[tablename].search([])
_logger.info("getAllDataset called for "+str(tablename)+" found : "+str(len(Dataset)))
else :
DomainEval = Domain
_logger.info("getAllDataset called for "+str(tablename)+" DomainEval "+str(DomainEval))
Dataset = self.env[tablename].search(DomainEval)
_logger.info("getAllDataset called for "+str(tablename)+" DomainEval "+str(DomainEval)+' found : '+str(len(Dataset)))
return Dataset
@api.model
def SendMail(self,MailEmpfaenger,MailEmpfaengerCC,MailEmpfaengerBCC,MailTemplate,MailSender,has_attachments=False,attachmentlist=[],with_confirm=False,Dataset=None):
if Dataset is None:
sampletable = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_table')
sampleid = self.env['ir.config_parameter'].sudo().get_param('dss.global.trigger_sample_id')
Dataset = self.env[sampletable].search([('id','=',sampleid)])
email_template = self.env['mail.template'].search([('id','=',MailTemplate)])
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Template : '+str(email_template)+" Empfänger :"+str(MailEmpfaenger)+'/'+str(MailEmpfaengerCC)+' von '+str(MailSender)+' -> '+str(Dataset))
if email_template:
ccmailto = email_template.email_cc
ccmailto_org = email_template.email_cc
bccmailto = email_template.email_bcc
bccmailto_org = email_template.email_bcc
if not ccmailto:
ccmailto = ''
if not bccmailto:
bccmailto = ''
if MailEmpfaengerCC:
ccmailto = ccmailto+', '+MailEmpfaengerCC
if MailEmpfaengerBCC:
bccmailto = bccmailto+', '+MailEmpfaengerBCC
if not MailEmpfaenger:
mailto = "technik@logumedia.de"
else:
mailto = MailEmpfaenger
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - vor CC Add')
if 'contract_writer_mailcc' in Dataset._fields:
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - in CC Add')
mailcc = Dataset["contract_writer_mailcc"]
if mailcc:
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - vor CC Add deep')
VsPartner = self.env['res.partner'].search([('id','=',Dataset.contract_writer.id)])
ccmailto = ccmailto+';'+VsPartner.email
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email CC Writer - FIX Empfänger : '+str(VsPartner)+' -> '+str(ccmailto)+' + '+str(VsPartner.email))
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Template : '+str(email_template)+" Empfänger :"+str(mailto)+'/'+str(ccmailto)+' -> '+str(Dataset))
email_template.email_to = mailto
email_template.email_cc = ccmailto
email_template.email_bcc = bccmailto
if has_attachments:
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Anhang : '+str(attachmentlist))
attachments = []
for mediatype in attachmentlist:
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Anhang : '+str(mediatype))
single_attachment = Dataset.get_attachments_by_mediatype_id(mediatype)
if single_attachment:
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Anhang erzeugen : '+str(single_attachment))
if single_attachment.binary_filename:
fname = single_attachment.binary_filename
else:
fname = single_attachment.binary_name
att_id = self.env['ir.attachment'].create({'name': fname,'datas': single_attachment.binary_binary})
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Anhang wurde erzeugen : '+str(att_id))
email_template.attachment_ids = [(4, att_id.id)]
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Anhang neu : '+str(email_template.attachment_ids))
if not with_confirm:
email_template.send_mail(Dataset.id,force_send=True)
else:
action = (self.env["confirmation.wizard"].confirm_message(
_("Möchten Sie die EMail versenden ?"),email_template, # One or more records
title="Bestätigen",method="Email senden ",callback_params={"Email": mailto}))
if action:
email_template.send_mail(Dataset.id,force_send=True)
email_template.attachment_ids = [(5,0,0)] # Clear attachments after sending
email_template.email_cc = ccmailto_org
email_template.email_bcc = bccmailto_org
return True
class dsstriggerconditions(models.Model):
@ -61,8 +350,6 @@ class dsstriggerconditions(models.Model):
trigger_marker_check = fields.Many2one('dss.marker','Marker',help='Welcher Marker soll eingefügt werden ?',tracking=True)
trigger_value = fields.Char('Fix Wert',tracking=True)
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
@ -183,89 +470,118 @@ class dsstriggergroups(models.Model):
if trig.trigger_active:
_logger.info("Trigger in run_triggers - Working on : "+str(trig.triggername)+'('+str(trig.id)+')')
dochecktrigger = False
if (changes == False):
dochecktrigger = True
elif (trig.triggertyp == "COND"):
dochecktrigger = True
if trig.trigger_is_block_config or trig.trigger_is_source_config:
localdict = {
'self': self,
'trigger': trigger,
'null': None,
'ChangeList': changes,
'CheckChange': trigger.CheckChange,
'date': date,
'datetime': datetime,
'relativedelta': relativedelta,
'execType': 'DATA',
}
_logger.info("Trigger in run_triggers - Blockly or Source Trigger : "+str(trig.triggername)+'('+str(trig.id)+')')
if trig.trigger_is_block_config:
_logger.info("Trigger in run_triggers - Blockly Trigger : "+str(trig.triggername)+'('+str(trig.id)+') -> '+str(trig.trigger_block_config))
if (trig.trigger_block_command_uptodate) :
try:
exec(trig.trigger_block_command,localdict)
except Exception as e:
_logger.error("Trigger in run_triggers - Blockly Trigger Error : "+str(e)+' -> '+str(trig.trigger_block_config))
else:
_logger.error("Trigger in run_triggers - Blockly Trigger Error : Command not uptodate : "+str(trig.trigger_block_command_uptodate)+' -> '+str(trig.trigger_block_config))
if trig.trigger_is_source_config:
_logger.info("Trigger in run_triggers - Source Trigger : "+str(trig.triggername)+'('+str(trig.id)+') -> '+str(trig.trigger_source_config))
try:
exec(trig.trigger_source_config, {}, localdict)
except Exception as e:
_logger.error("Trigger in run_triggers - Source Trigger Error : "+str(e)+' -> '+str(trig.trigger_source_config))
continue
else:
if (trig.trigger_field.name in changes):
dochecktrigger = True
if (dochecktrigger):
isinintitable = self.env['dss.triggermodel.execute'].search(['&',('trigger','=',trig.id),('data_uuid','=',Dataset.uuid)])
dotrigger = False
if (not isinintitable) and trig.trigger_init_trigger:
_logger.info("Trigger in run_triggers - first run and allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = True
elif (not isinintitable) and ((not trig.trigger_init_trigger) and (not trig.trigger_onlyinit_trigger)):
_logger.info("Trigger in run_triggers - first run but not allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = False
elif (isinintitable) and trig.trigger_onlyinit_trigger:
_logger.info("Trigger in run_triggers - not first run but only first: "+str(isinintitable)+' -> '+str(trig.trigger_onlyinit_trigger)+' -> '+str(trig))
dotrigger = False
if (changes == False):
dochecktrigger = True
elif (trig.triggertyp == "COND"):
dochecktrigger = True
else:
_logger.info("Trigger in run_triggers - not first run but only first: "+str(isinintitable)+' -> '+str(trig))
dotrigger = True
if dotrigger:
fieldname = trig.trigger_value_field.name
_logger.info("Trigger in run_triggers - checking conditions : "+str(trig.triggertyp)+" field : "+str(fieldname)+' -> '+str(trig.trigger_value_field))
if (trig.triggertyp == "FIELD_B"):
Wert = Dataset[fieldname]
_logger.info("Trigger in run_triggers - Boolean check : "+str(Dataset[fieldname])+" vs "+str(Wert)+' -> '+str(trig.trigger_value_Bool))
if trig.trigger_value_Bool:
if Wert:
_logger.info("Trigger in run_triggers - value true - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = True
else:
_logger.info("Trigger in run_triggers - value true - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = False
else:
if Wert:
_logger.info("Trigger in run_triggers - value False - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = False
else:
_logger.info("Trigger in run_triggers - value False - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = True
elif (trig.triggertyp == "FIELD_S"):
#Wert= self.env[trig.trigger_table.model].get(fieldname)
WertDB = self.env[trig.trigger_table.model].search([('id', '=', Dataset.id)])
field = WertDB._fields[fieldname]
field_type = field.type
Wert = ""
if field_type=="many2one":
Wert = str(Dataset[fieldname].id)
# Dataset[fieldname].model
# SubWertDB = self.env[].search([('id', '=', field.id)])
# Wert = SubWertDB.id
if field_type=="char":
Wert = str(Dataset[fieldname])
_logger.info("Trigger in run_triggers - specific value : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value)+' - '+str(field)+' / '+str(field_type))
if (str(Wert) == str(trig.trigger_value)):
_logger.info("Trigger in run_triggers - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value))
dotrigger = True
else:
_logger.info("Trigger in run_triggers - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value))
dotrigger = False
elif (trig.triggertyp == "FIELD_K"):
dotrigger = False
elif (trig.triggertyp == "MANUAL"):
dotrigger = False
elif (trig.triggertyp == "COND"):
if (trig.trigger_field.name in changes):
dochecktrigger = True
if (dochecktrigger):
isinintitable = self.env['dss.triggermodel.execute'].search(['&',('trigger','=',trig.id),('data_uuid','=',Dataset.uuid)])
dotrigger = False
if (not isinintitable) and trig.trigger_init_trigger:
_logger.info("Trigger in run_triggers - first run and allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = True
elif (not isinintitable) and ((not trig.trigger_init_trigger) and (not trig.trigger_onlyinit_trigger)):
_logger.info("Trigger in run_triggers - first run but not allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = False
elif (isinintitable) and trig.trigger_onlyinit_trigger:
_logger.info("Trigger in run_triggers - not first run but only first: "+str(isinintitable)+' -> '+str(trig.trigger_onlyinit_trigger)+' -> '+str(trig))
dotrigger = False
else:
_logger.info("Trigger in run_triggers - not first run but only first: "+str(isinintitable)+' -> '+str(trig))
dotrigger = True
if dotrigger:
fieldname = trig.trigger_value_field.name
_logger.info("Trigger in run_triggers - checking conditions : "+str(trig.triggertyp)+" field : "+str(fieldname)+' -> '+str(trig.trigger_value_field))
if (trig.triggertyp == "FIELD_B"):
Wert = Dataset[fieldname]
_logger.info("Trigger in run_triggers - Boolean check : "+str(Dataset[fieldname])+" vs "+str(Wert)+' -> '+str(trig.trigger_value_Bool))
if trig.trigger_value_Bool:
if Wert:
_logger.info("Trigger in run_triggers - value true - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = True
else:
_logger.info("Trigger in run_triggers - value true - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = False
else:
if Wert:
_logger.info("Trigger in run_triggers - value False - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = False
else:
_logger.info("Trigger in run_triggers - value False - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value_Bool))
dotrigger = True
elif (trig.triggertyp == "FIELD_S"):
#Wert= self.env[trig.trigger_table.model].get(fieldname)
WertDB = self.env[trig.trigger_table.model].search([('id', '=', Dataset.id)])
field = WertDB._fields[fieldname]
field_type = field.type
Wert = ""
if field_type=="many2one":
Wert = str(Dataset[fieldname].id)
# Dataset[fieldname].model
# SubWertDB = self.env[].search([('id', '=', field.id)])
# Wert = SubWertDB.id
if field_type=="char":
Wert = str(Dataset[fieldname])
_logger.info("Trigger in run_triggers - specific value : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value)+' - '+str(field)+' / '+str(field_type))
if (str(Wert) == str(trig.trigger_value)):
_logger.info("Trigger in run_triggers - specific value found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value))
dotrigger = True
else:
_logger.info("Trigger in run_triggers - specific value not found : "+str(changes)+" ("+str(Wert)+') -> '+str(trig.trigger_value))
dotrigger = False
elif (trig.triggertyp == "FIELD_K"):
dotrigger = False
elif (trig.triggertyp == "MANUAL"):
dotrigger = False
elif (trig.triggertyp == "COND"):
dotrigger = True
if trig.trigger_plus_conditions and dotrigger:
runtrigger = True
for SingleC in trig.trigger_conditions:
_logger.info("Trigger in run_triggers - Multible Conditions found "+str(trig.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runtrigger))
runtrigger = SingleC.trigger_CheckCond(Dataset,SingleC) and runtrigger
else:
runtrigger = dotrigger
if trig.trigger_plus_conditions and dotrigger:
runtrigger = True
for SingleC in trig.trigger_conditions:
_logger.info("Trigger in run_triggers - Multible Conditions found "+str(trig.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runtrigger))
runtrigger = SingleC.trigger_CheckCond(Dataset,SingleC) and runtrigger
else:
runtrigger = dotrigger
if runtrigger:
execds = ''
self.trigger_run(trig,Dataset,isinintitable,execds)
if runtrigger:
execds = ''
self.trigger_run(trig,Dataset,isinintitable,execds)
def trigger_run(self,trig,Dataset,isinintitable,execds):
for akt in trig.trigger_aktionen:
@ -304,68 +620,93 @@ class dsstriggergroups(models.Model):
for trig in triggers:
triggercnt += 1
resultstr = resultstr+" Trigger "+str(triggercnt)+' : '
if (trig.triggertyp == "FILTER"):
if trig.trigger_is_block_config or trig.trigger_is_source_config:
localdict = {
'self': self,
'null': None,
'trigger': trigger,
'date': date,
'datetime': datetime,
'relativedelta': relativedelta,
'execType': 'CRON',
}
_logger.info("Trigger in run_cron_triggers - Blockly or Source Trigger : "+str(trig.triggername)+'('+str(trig.id)+')')
if trig.trigger_is_block_config:
_logger.info("Trigger in run_cron_triggers - Blockly Trigger : "+str(trig.triggername)+'('+str(trig.id)+') -> '+str(trig.trigger_block_config))
if (trig.trigger_block_command_uptodate) :
try:
exec(trig.trigger_block_command,localdict)
except Exception as e:
_logger.error("Trigger in run_cron_triggers - Blockly Trigger Error : "+str(e)+' -> '+str(trig.trigger_block_config))
else:
_logger.error("Trigger in run_cron_triggers - Blockly Trigger Error : Command not uptodate : "+str(trig.trigger_block_command_uptodate)+' -> '+str(trig.trigger_block_config))
if trig.trigger_is_source_config:
_logger.info("Trigger in run_cron_triggers - Source Trigger : "+str(trig.triggername)+'('+str(trig.id)+') -> '+str(trig.trigger_source_config))
try:
exec(trig.trigger_source_config, {}, localdict)
except Exception as e:
_logger.error("Trigger in run_cron_triggers - Source Trigger Error : "+str(e)+' -> '+str(trig.trigger_source_config))
continue
else:
if (trig.triggertyp == "FILTER"):
lea=trig.trigger_raw_condition.split(',')
_logger.info("Trigger in run_Cron_triggers - : Filtered Datasets "+str(lea))
AllDataset = self.env[str(triggergroup.trigger_table.model)].search([lea])
else:
else:
AllDataset = self.env[str(triggergroup.trigger_table.model)].search([])
_logger.info("Trigger in run_Cron_triggers - : All Datasets "+str(len(AllDataset)))
resultstr = " Count Data : "+str(len(AllDataset))
for Dataset in AllDataset:
dscnt += 1
resultstr = resultstr+" Data "+str(dscnt)+' : '
_logger.info("Trigger in run_Cron_triggers - : "+str(Dataset)+" check allready execute : "+str(Dataset.uuid)+" "+str(date.today()))
isinintitable = self.env['dss.triggermodel.execute'].search(['&',('trigger','=',trig.id),('data_uuid','=',Dataset.uuid),('execdatetime','=',date.today())])
dotrigger = False
if (not isinintitable) and trig.trigger_init_trigger:
_logger.info("Trigger in run_Cron_triggers - first run and allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = True
elif (not isinintitable) and ((not trig.trigger_init_trigger) and (not trig.trigger_onlyinit_trigger)):
_logger.info("Trigger in run_Cron_triggers - first run but not allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = False
elif (isinintitable) and trig.trigger_onlyinit_trigger:
_logger.info("Trigger in run_Cron_triggers - not first run but only first (or day): "+str(isinintitable)+' -> '+str(trig.trigger_onlyinit_trigger)+' -> '+str(trig))
resultstr = " Count Data : "+str(len(AllDataset))
for Dataset in AllDataset:
dscnt += 1
resultstr = resultstr+" Data "+str(dscnt)+' : '
_logger.info("Trigger in run_Cron_triggers - : "+str(Dataset)+" check allready execute : "+str(Dataset.uuid)+" "+str(date.today()))
isinintitable = self.env['dss.triggermodel.execute'].search(['&',('trigger','=',trig.id),('data_uuid','=',Dataset.uuid),('execdatetime','=',date.today())])
dotrigger = False
else:
_logger.info("Trigger in run_Cron_triggers - running no given restrictions : "+str(isinintitable)+' -> '+str(trig))
dotrigger = True
if dotrigger:
cntExecDS_init += 1
if (trig.triggertyp == "FILTER"):
runtrigger = True
elif (trig.triggertyp == "COND"):
runtrigger = True
for SingleC in trig.trigger_conditions:
cntExecCont += 1
_logger.info("Trigger in run_Cron_triggers - Multible Conditions found "+str(trig.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runtrigger))
conres = SingleC.trigger_CheckCond(Dataset,SingleC)
runtrigger = conres and runtrigger
if conres:
cntExecContTrue += 1
if (not isinintitable) and trig.trigger_init_trigger:
_logger.info("Trigger in run_Cron_triggers - first run and allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = True
elif (not isinintitable) and ((not trig.trigger_init_trigger) and (not trig.trigger_onlyinit_trigger)):
_logger.info("Trigger in run_Cron_triggers - first run but not allowed : "+str(isinintitable)+' -> '+str(trig.trigger_init_trigger)+' -> '+str(trig))
dotrigger = False
elif (isinintitable) and trig.trigger_onlyinit_trigger:
_logger.info("Trigger in run_Cron_triggers - not first run but only first (or day): "+str(isinintitable)+' -> '+str(trig.trigger_onlyinit_trigger)+' -> '+str(trig))
dotrigger = False
else:
_logger.info("Trigger Abgebrochen ! in ZeitGruppen sind nur BedingungsTrigger Erlaubt "+str(trig.trigger_aktionen))
runtrigger = False
_logger.info("Trigger in run_Cron_triggers - Conditions result "+str(runtrigger))
if runtrigger:
cntExecDS += 1
_logger.info("Trigger wird Ausgeführt - Aktionen "+str(trig.trigger_aktionen))
resultstr = resultstr + " Anz Aktionen : "+str(len(trig.trigger_aktionen))
execds = self.trigger_run(trig,Dataset,isinintitable,execds)
_logger.info("Result :"+resultstr)
_logger.info("-------------------------------------- CRON Trigger Result --------------------------------------------------------------------")
_logger.info("Result :"+resultsimplestr)
_logger.info("Result : Anz. CondChecks : "+str(cntExecDS_init))
_logger.info("Result : Anz. Conditions : "+str(cntExecCont))
_logger.info("Result : Anz. ConditionsTrue : "+str(cntExecContTrue))
_logger.info("Result : Anz. ConditionsFalse : "+str(cntExecCont - cntExecContTrue))
_logger.info("Result : Anz. Conditionok : "+str(cntExecDS))
_logger.info("Result : Anz. ExecAction : "+str(cntExecAS))
_logger.info("Result : Exec Datasets : "+execds)
_logger.info("-------------------------------------------------------------------------------------------------------------------------------")
_logger.info("Trigger in run_Cron_triggers - running no given restrictions : "+str(isinintitable)+' -> '+str(trig))
dotrigger = True
if dotrigger:
cntExecDS_init += 1
if (trig.triggertyp == "FILTER"):
runtrigger = True
elif (trig.triggertyp == "COND"):
runtrigger = True
for SingleC in trig.trigger_conditions:
cntExecCont += 1
_logger.info("Trigger in run_Cron_triggers - Multible Conditions found "+str(trig.trigger_conditions)+' -> '+str(SingleC)+' -> '+str(runtrigger))
conres = SingleC.trigger_CheckCond(Dataset,SingleC)
runtrigger = conres and runtrigger
if conres:
cntExecContTrue += 1
else:
_logger.info("Trigger Abgebrochen ! in ZeitGruppen sind nur BedingungsTrigger Erlaubt "+str(trig.trigger_aktionen))
runtrigger = False
_logger.info("Trigger in run_Cron_triggers - Conditions result "+str(runtrigger))
if runtrigger:
cntExecDS += 1
_logger.info("Trigger wird Ausgeführt - Aktionen "+str(trig.trigger_aktionen))
resultstr = resultstr + " Anz Aktionen : "+str(len(trig.trigger_aktionen))
execds = self.trigger_run(trig,Dataset,isinintitable,execds)
# _logger.info("Result :"+resultstr)
# _logger.info("-------------------------------------- CRON Trigger Result --------------------------------------------------------------------")
# _logger.info("Result :"+resultsimplestr)
# _logger.info("Result : Anz. CondChecks : "+str(cntExecDS_init))
# _logger.info("Result : Anz. Conditions : "+str(cntExecCont))
# _logger.info("Result : Anz. ConditionsTrue : "+str(cntExecContTrue))
# _logger.info("Result : Anz. ConditionsFalse : "+str(cntExecCont - cntExecContTrue))
# _logger.info("Result : Anz. Conditionok : "+str(cntExecDS))
# _logger.info("Result : Anz. ExecAction : "+str(cntExecAS))
# _logger.info("Result : Exec Datasets : "+execds)
# _logger.info("-------------------------------------------------------------------------------------------------------------------------------")
def exectrigger(self):
@ -407,6 +748,7 @@ class dsstriggertypes(models.Model):
trigger_aktionen_groups = fields.Many2many('dss.triggeractions.groups',string='Aktionsgruppen bei auslösen des Triggers',tracking=True)
trigger_raw_condition = fields.Char('Datensatz Auswahl',tracking=True)
trigger_is_block_config = fields.Boolean('Blockly Trigger Design',tracking=True)
trigger_is_source_config = fields.Boolean('Pure Python Trigger',tracking=True)
trigger_block_config = fields.Char('Blockly Design',tracking=True)
trigger_block_raw_config = fields.Char('Blockly command Design',tracking=True)
trigger_block_command_uptodate = fields.Boolean('Blockly command aktuell',tracking=True)
@ -475,6 +817,20 @@ class dsstriggertypes(models.Model):
foundtrigger = self.env[modelid].search([])
_logger.info("Trigger get all !"+str(foundtrigger))
blocksyntax = []
if foundtrigger:
blocksyntax = [record.read()[0] for record in foundtrigger] if foundtrigger else []
else:
blocksyntax = []
_logger.info("Trigger get all !"+str(blocksyntax))
return blocksyntax
@api.model
def getall_filter(self,modelid,modelfilter):
_logger.info("Trigger get all !"+str(modelid))
foundtrigger = self.env[modelid].search([('model','=ilike',modelfilter)])
_logger.info("Trigger get all !"+str(foundtrigger))
blocksyntax = []
if foundtrigger:
blocksyntax = [record.read()[0] for record in foundtrigger] if foundtrigger else []
else:
@ -508,11 +864,17 @@ class dsstriggertypes(models.Model):
return newtrigger
@api.model
def UpdateBlockTrigger(self,triggername,blockcode,triggeraktiv ):
def UpdateBlockTrigger(self,triggername,blockcode,blockcommand,blockcommand_uptodate,triggertable,triggeraktiv ):
_logger.info("Trigger Update Block Trigger !"+str(triggername))
foundtrigger = self.env['dss.triggertypes'].search([('triggername','=',triggername)])
if foundtrigger:
foundtrigger.write({'trigger_block_raw_config':blockcode,'trigger_active':triggeraktiv,'trigger_block_command_uptodate':False})
triggertable_ = self.env['ir.model'].search([('model','=',str(triggertable))])
_logger.info("Trigger Update Block Trigger !"+str(triggername)+' -> '+str(triggertable_))
foundtrigger.trigger_block_raw_config = blockcode
foundtrigger.trigger_active = triggeraktiv
foundtrigger.trigger_block_command_uptodate=blockcommand_uptodate
foundtrigger.trigger_block_command=blockcommand
foundtrigger.trigger_table = triggertable_
return foundtrigger
@api.model
@ -523,8 +885,23 @@ class dsstriggertypes(models.Model):
_logger.info("Trigger Exec Trigger Test Dataset !"+str(Dataset))
self.env['ir.config_parameter'].sudo().set_param('dss.global.trigger_sample_table', sampletable)
self.env['ir.config_parameter'].sudo().set_param('dss.global.trigger_sample_id', sampleid)
exec(sourcecode)
return "OK"
self.env['ir.config_parameter'].sudo().set_param('dss.global.testmode', True)
self.env['ir.config_parameter'].sudo().set_param('dss.global.debugout','')
localdict = {
'trigger': trigger,
'self': self,
'null': None,
'ChangeList': [],
'date': date,
'datetime': datetime,
'relativedelta': relativedelta,
'execType': 'TEST',
}
exec(sourcecode,localdict)
self.env['ir.config_parameter'].sudo().set_param('dss.global.testmode', False)
Debugout = self.env['ir.config_parameter'].sudo().get_param('dss.global.debugout')
if (not Debugout): Debugout = ""
return Debugout+"\nOK"
except Exception as e:
_logger.error("Trigger Exec Trigger Test Error !"+str(e))
return "Error :"+str(e)
@ -645,7 +1022,7 @@ class dsstriggeractions(models.Model):
mailcc = Dataset["contract_writer_mailcc"]
if mailcc:
VsPartner = self.env['res.partner'].search([('id','=',Dataset.contract_writer.id)])
ccmailto = ccmailto+';'+VsPartner.email
ccmailto = ccmailto+','+VsPartner.email
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email CC Writer - FIX Empfänger : '+str(VsPartner)+' -> '+str(ccmailto)+' + '+str(VsPartner.email))
_logger.info('Trigger Aktion TRA_' + str(self)+' Sending Email - Template : '+str(self.email_template)+" Empfänger :"+str(mailto)+'/'+str(ccmailto)+' -> '+str(Dataset))
self.email_template.email_to = mailto
@ -784,10 +1161,27 @@ class dsstriggermodel(models.Model):
def _default_uuid(self):
return str(uuid.uuid4())
def serialize_sets(obj):
if isinstance(obj, set):
return list(obj)
return obj
@api.model
def trigger_track_template(self, changes, Dataset):
_logger.info("Trigger in track_template - "+str(Dataset)+" - Changes : "+str(changes))
hook = self.env['dss.settings.vars'].search([('varname','=','N8NWebhook-OnChange')])
if hook:
if hook.varvalue:
_logger.info("Trigger in track_template - N8NWebhook-OnChange - "+str(Dataset.triggergroup)+" - Changes : "+str(changes))
# Call N8N Webhook
try:
webhook_url = hook.varvalue
payload = {"event": "on_change", "data": {'dataset_name':Dataset._name,'dataset_id':Dataset.id,'changes':json.dumps(set(changes),default=dsstriggermodel.serialize_sets)}}
response = requests.post(webhook_url, json=payload, headers={'Content-Type': 'application/json'})
_logger.info("Trigger in track_template - N8NWebhook-OnChange - Webhook Response: "+str(response.status_code)+" - "+str(response.text))
except Exception as e:
_logger.error("Trigger in track_template - N8NWebhook-OnChange - Webhook Error: "+str(e))
if Dataset.run_trigger:
_logger.info("Trigger in track_template - "+str(Dataset.triggergroup)+" - Changes : "+str(changes))
Dataset.triggergroup.run_triggers(changes, Dataset, Dataset.triggergroup.triggers)

54
models/dss_web_contracts_all.py Executable file
View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*
# Test
# Test2
import ast
import datetime
import json
import re
import uuid
import logging
import base64
import subprocess
import tempfile
import easywebdav
import os
import os.path
from odoo import api, fields, models, _
from odoo import tools
from . import dss_settings
from . import dss_ads
from odoo.exceptions import ValidationError
from datetime import date
from datetime import datetime
from babel.dates import format_date
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
import sys
TUYA_LOGGER.setLevel(logging.DEBUG)
_logger = logging.getLogger(__name__)
class dsswebcontracts_all(models.Model):
_name = "dss.web_contracts.all"
_description = "DigitalSignage Web_Vertraege all"
_inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
# def action_send_email(self):
# """ Sendet eine E-Mail mit den Inhalten des Objekts """
# template = self.env.ref('dss.email_template_my_model')
# if template:
#
#
# template.send_mail(self.id, force_send=True)

View File

@ -0,0 +1,283 @@
# -*- coding: utf-8 -*
# Test
# Test2
import ast
import datetime
import json
import re
import uuid
import logging
import base64
import subprocess
import tempfile
import easywebdav
import os
import os.path
from odoo import api, fields, models, _
from odoo import tools
from . import dss_settings
from . import dss_ads
from odoo.exceptions import ValidationError
from datetime import date
from datetime import datetime
from babel.dates import format_date
from dateutil.relativedelta import relativedelta
from pyffmpeg import FFmpeg
from tuya_iot import TuyaOpenAPI, TUYA_LOGGER
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER
import sys
TUYA_LOGGER.setLevel(logging.DEBUG)
_logger = logging.getLogger(__name__)
class dsswebcontracts_stream(models.Model):
_name = "dss.web_contracts.stream"
_description = "DigitalSignage Web_Vertraege Stream"
_rec_name = "contract_auto_name"
_inherit = ['mail.thread','mail.activity.mixin','dss.triggermodel']
uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID')
cruuid = fields.Char(related='uuid')
contract_id = fields.Char("Kundennummer",store=True,tracking=True)
contract_auto_id = fields.Char("Kundennummer automatisch",tracking=True,help="Wird berechnet aus Projektnummer + Kunden ID")
contract_name = fields.Char('Kurzbezeichnung', required=True,tracking=True)
contract_auto_name = fields.Char('Vertragskennung',tracking=True,help="Wird berechnet aus Kundennummer + Vertragskennung")
contract_date = fields.Date('Vertragsdatum',tracking=True)
contract_writer = fields.Many2one('res.partner', domain="['&',('dsspartner','=',True),('dsspartner_vertrieb','=',True)]", tracking=True)
contract_writer_formular = fields.Char('Vertragsschreiber Formular', tracking=True)
#contract_type = fields.Selection([('TV','TV'),('Web','Web')], 'Vertragstyp', tracking=True)
#contract_writer_projects = fields.Many2many('dss.projects',string="Vertragsschreiber Projekte", tracking=True, compute='_get_contractwriter_projects', store=True)
contract_writer_projects_string = fields.Char("Vertragsschreiber Projekte S", tracking=True)
contract_writer_projects_MM = fields.Many2many('dss.projects',string="Vertragsschreiber Projekte MM", tracking=True, domain="[('id','in',self.env.user.dss_projects.ids)]", store=True)
websideusername = fields.Char('Webseite Benutzername',tracking=True,compute='_compute_websideusername', store=True)
werbe_feld = fields.Char(string='Werbefelde(r)',tracking=True)
werbe_feld_selected = fields.Many2many('dss.advertisefields',string='Werbefelder',tracking=True)
remark = fields.Char('Bemerkungen',tracking=True)
contract_remark = fields.Html('Vertragshinweise',tracking=True)
project = fields.Many2one('dss.projects' , string='Project', store=True,tracking=True)
project_id = fields.Integer(related='project.projectid', string='Project ID')
projectIid = fields.Integer('Project IID',tracking=True)
client = fields.Many2one('res.partner',string="Kunde (wenn angelegt)",domain="['&',('dsspartner','=',True),('dsspartner_werbung','=',True)]",tracking=True,help="Nur zu Benutzen wenn Kunden als Kontakt angelegt wurde")
client_id = fields.Char(string="KundenID (2Stellen)",help="Nur der 2 stellige letzte Teil der Kundennummer",tracking=True)
client_short_company = fields.Char('Firmenname Kunde',tracking=True)
client_short_vorname = fields.Char('Vorname Kunde',tracking=True)
client_short_name = fields.Char('Name Kunde',tracking=True)
client_short_strasse = fields.Char('Strasse Kunde',tracking=True)
client_short_plz = fields.Char('PLZ Kunde',tracking=True)
client_short_ort = fields.Char('Ort Kunde',tracking=True)
client_short_land = fields.Many2one('res.country','Land Kunde',tracking=True)
client_short_email = fields.Char('Email Kunde',tracking=True)
client_short_finemail = fields.Char('Rechnungs Email Kunde',tracking=True)
client_short_telefon = fields.Char('Telefon Kunde',tracking=True)
client_short_mobil = fields.Char('Mobilfunk Kunde',tracking=True)
client_short_website = fields.Char('Webseite Kunde',tracking=True)
client = fields.Many2one('res.partner',string="Kunde (wenn angelegt)",domain="['&',('dsspartner','=',True),('dsspartner_werbung','=',True)]",tracking=True,help="Nur zu Benutzen wenn Kunden als Kontakt angelegt wurde")
bookingpack = fields.Char(string='Packet',tracking=True)
runtime_m = fields.Integer('Laufzeit Monate',tracking=True)
boarding = fields.Boolean(string='Boarding',tracking=True)
grafikerstellung = fields.Boolean(string='Grafik',tracking=True)
payment = fields.Selection([('FULL','Gesamtzahlung')],string='Zahlung',tracking=True)
reach_PLZ = fields.Char('Reichweite PLZ',tracking=True)
grafik_zuarbeitBis = fields.Date("Zuarbeit bis", tracking=True)
date_start_planed = fields.Date(string='geplantes Startdatum', tracking=True)
date_remove_planed = fields.Date(string='geplantes Enddatum', tracking=True)
scan_vertrag = fields.Binary('Datei')
file_name = fields.Char(string='Dateiname')
erfasst_in_odoo = fields.Boolean('In Odoo erfasst')
erfasst_in_agenda = fields.Boolean('In Agenda erfasst')
# def action_send_email(self):
# """ Sendet eine E-Mail mit den Inhalten des Objekts """
# template = self.env.ref('dss.email_template_my_model')
# if template:
#
#
# template.send_mail(self.id, force_send=True)
def _get_contractwriter_projects(self):
if self.env.user:
self.contract_writer_projects = self.env.user.dss_projects.ids
else:
self.contract_writer_projects = False
def _compute_websideusername(self):
self.websideusername = self.env.user.name
def pydonewpartner1(self):
_logger.info("create new partner...")
@api.model
def _default_uuid(self):
return str(uuid.uuid4())
def pydonewpartner(self):
_logger.info("create new partner...")
fullname = str(self.client_short_vorname) + ' ' +str(self.client_short_name)
newcontact = self.env['res.partner'].create({'name': fullname,
'dsspartner_vorname': self.client_short_vorname,
'dsspartner_name': self.client_short_name,
'email': self.client_short_email,
'phone': self.client_short_telefon,
'mobile': self.client_short_mobil,
'street': self.client_short_strasse,
'city': self.client_short_ort,
'zip': self.client_short_plz,
'country_id': self.env['res.country'].search([('code', '=', 'DE')], limit=1).id,
'company_type': 'person', # 'company' oder 'person',
'website': self.client_short_website,
'company_name': self.client_short_company,
'dsspartner': True,
'dsspartner_werbung': True
})
self.client = newcontact.id
def pydonewcontract_streaming(self):
_logger.info("create new contract...")
bookingpack = fields.Char(string='Packet',tracking=True)
werbe_feld = self.project_id + '_'+self.bookingpack
werbe_feld_selected = self.env['dss.advertisefields'].search([('id','in',self.werbe_feld_selected.ids)])
if not werbe_feld_selected:
_logger.info("kein Werbefeld ausgewählt, Abbruch...")
return
else :
newcontract = self.env['dss.contracts'].create({'project_id': self.project_id,
'project': self.project.id,
'client_id': self.client_id,
'contract_auto_name': self.contract_auto_name,
'contract_auto_id': self.contract_auto_id,
'contract_name': self.contract_name,
'contract_state': self.env['dss.contractstate'].search([("statusname","=","Angelegt")]).id,
'paymentinterval': self.paymentinterval.id,
'werbe_feld_selected': self.werbe_feld_selected,
'client': self.client.id,
'client_short_vorname': self.client_short_vorname,
'client_short_name': self.client_short_name,
'client_short_email': self.client_short_email,
'client_short_telefon': self.client_short_telefon,
'client_short_mobil': self.client_short_mobil,
'client_short_strasse': self.client_short_strasse,
'client_short_ort': self.client_short_ort,
'client_short_plz': self.client_short_plz,
'client_short_website': self.client_short_website,
'client_short_company': self.client_short_company,
'runtimesystem': 'M',
'runtime_m': self.runtime_m,
'contract_auto_extend': False,
'contract_cancel_date': False,
'runtime_events': False,
'tv_reach_PLZ': self.reach_PLZ,
'web_contract':self.id,
'contract_auto_extend': self.contract_auto_extend,
'contract_date': self.contract_date,
'work_state_info': self.remark,
'scan_vertrag': self.scan_vertrag,
'contract_grafik': self.grafikerstellung,
'contract_boarding': self.boarding,
'grafik_zuarbeitBis': self.grafik_zuarbeitBis
# payment = fields.Selection([('FULL','Gesamtzahlung')],string='Zahlung',tracking=True)
})
_logger.info("create new Werbekampagne...")
newWK = self.env['dss.ads'].create({'contract': newcontract.id,
'project': newcontract.project.id,
'adname': 'WK '+self.contract_auto_name,
'adtype': 'MAIN',
'date_start_planed': self.date_start_planed,
'date_remove_planed': self.date_remove_planed,
#'work_state_info': 'ZA bis: '+str(self.grafik_zuarbeitBis)+' / '+self.remark
'work_state_info': 'ZA bis: '+format_date(self.grafik_zuarbeitBis,format='dd.MM.yy',locale='de_DE')
})
self.erfasst_in_odoo = True
#Vertragskennungen bei onChange anpassen
@api.onchange('client_id')
def _onchange_client_id(self):
for record in self :
if record.contract_name == '' :
cname = 'unbekannter Kunden'
else:
cname = record.contract_name
resstr = "%s%s %s" % (record.project_id,record.client_id,cname)
cidstr = "%s%s" % (record.project_id,record.client_id)
if resstr is None :
resstr = 'nicht ermittelbar'
_logger.info('Contract_client_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name))
self.contract_auto_name = resstr
self.contract_auto_id = cidstr
@api.onchange('project_id')
def _onchange_project_id(self):
for record in self :
if record.contract_name == '' :
cname = 'unbekannter Kunden'
else:
cname = record.contract_name
resstr = "%s%s %s" % (record.project_id,record.client_id,cname)
cidstr = "%s%s" % (record.project_id,record.client_id)
if resstr is None :
resstr = 'nicht ermittelbar'
_logger.info('project_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name))
self.contract_auto_name = resstr
self.contract_auto_id = cidstr
# @api.onchange('project')
# def _onchange_project(self):
# self.project_id = self.project.project_id
@api.onchange('contract_name')
def _onchange_contract_name(self):
for record in self :
if record.contract_name == '' :
cname = 'unbekannter Kunden'
else:
cname = record.contract_name
resstr = "%s%s %s" % (record.project_id,record.client_id,cname)
cidstr = "%s%s" % (record.project_id, record.client_id)
if resstr is None :
resstr = 'nicht ermittelbar'
_logger.info('Contract_Name_Change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name))
if not self.contract_auto_name:
self.contract_auto_name = resstr
if not self.contract_auto_id:
self.contract_auto_id = cidstr
if self.contract_auto_id == "":
self.contract_auto_id = cidstr
@api.onchange('contract_auto_id')
def _onchange_contract_auto_id(self):
for record in self :
if record.contract_name == '' :
cname = 'unbekannter Kunden'
else:
cname = record.contract_name
resstr = "%s%s %s" % (record.project_id,record.client_id,cname)
cidstr = "%s%s" % (record.project_id, record.client_id)
if resstr is None:
resstr = 'nicht ermittelbar'
_logger.info('Contract_auto_id_change : C_' + str(self.id) + ' - '+str(cidstr)+' vs. '+str(self.contract_auto_id)+'/'+str(resstr)+' vs '+str(self.contract_auto_name))
if not self.contract_auto_name:
self.contract_auto_name = resstr
if not self.contract_auto_id:
self.contract_auto_id = cidstr
if self.contract_auto_id == "":
self.contract_auto_id = cidstr

1
models/utils.py Normal file
View File

@ -0,0 +1 @@

View File

@ -36,6 +36,7 @@ digitalsignage_dss_provisionstypen_group_user,access.dss.provisionstypen,model_d
digitalsignage_dss_payintervals_group_user,access.dss.payintervals,model_dss_payintervals,base.group_user,1,1,1,1
digitalsignage_dss_importinvoicelist_group_user,access.dss.importinvoicelist,model_dss_importinvoicelist,base.group_user,1,1,1,1
digitalsignage_dss_web_contracts_group_user,access.dss_web_contracts,model_dss_web_contracts,base.group_user,1,1,1,1
digitalsignage_dss_web_contracts_stream_group_user,access.dss_web_contracts_stream,model_dss_web_contracts_stream,base.group_user,1,1,1,1
digitalsignage_dss_contracts_ads_topics_group_user,access.dss_contracts_ads_topics,model_dss_contracts_ads_topics,base.group_user,1,1,1,1
digitalsignage_dss_triggerconditions_group_user,access.dss.triggerconditions,model_dss_triggerconditions,base.group_user,1,1,1,1
digitalsignage_dss_marker_group_user,access.dss.marker,model_dss_marker,base.group_user,1,1,1,1
@ -52,4 +53,8 @@ digitalsignage_dss_triggeractions_groups_group_user,access.dss.triggeractions.gr
digitalsignage_dss_screendesign_group_user,access.dss.screendesign,model_dss_screendesign,base.group_user,1,1,1,1
digitalsignage_dss_binaries_group_user,access.dss.binaries,model_dss_binaries,base.group_user,1,1,1,1
digitalsignage_dss_binaries_wizard_new_group_user,access.dss.binaries.wizard.new,model_dss_binaries_wizard_new,base.group_user,1,1,1,1
digitalsignage_dss_linkmail_group_user,access.dss.linkmail,model_dss_linkmail,base.group_user,1,1,1,1
digitalsignage_dss_linkmail_group_user,access.dss.linkmail,model_dss_linkmail,base.group_user,1,1,1,1
digitalsignage_dss_kileads_requests,access.dss.kileads.requests,model_dss_kileads_requests,base.group_user,1,1,1,1
digitalsignage_dss_kileads,access.dss.kileads,model_dss_kileads,base.group_user,1,1,1,1
digitalsignage_dss_contracts_uservars_group_user,access.dss.contracts_uservars,model_dss_contracts_uservars,base.group_user,1,1,1,1
digitalsignage_dss_settings_vars_group_user,access.dss.settings.vars,model_dss_settings_vars,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
36 digitalsignage_dss_payintervals_group_user access.dss.payintervals model_dss_payintervals base.group_user 1 1 1 1
37 digitalsignage_dss_importinvoicelist_group_user access.dss.importinvoicelist model_dss_importinvoicelist base.group_user 1 1 1 1
38 digitalsignage_dss_web_contracts_group_user access.dss_web_contracts model_dss_web_contracts base.group_user 1 1 1 1
39 digitalsignage_dss_web_contracts_stream_group_user access.dss_web_contracts_stream model_dss_web_contracts_stream base.group_user 1 1 1 1
40 digitalsignage_dss_contracts_ads_topics_group_user access.dss_contracts_ads_topics model_dss_contracts_ads_topics base.group_user 1 1 1 1
41 digitalsignage_dss_triggerconditions_group_user access.dss.triggerconditions model_dss_triggerconditions base.group_user 1 1 1 1
42 digitalsignage_dss_marker_group_user access.dss.marker model_dss_marker base.group_user 1 1 1 1
53 digitalsignage_dss_screendesign_group_user access.dss.screendesign model_dss_screendesign base.group_user 1 1 1 1
54 digitalsignage_dss_binaries_group_user access.dss.binaries model_dss_binaries base.group_user 1 1 1 1
55 digitalsignage_dss_binaries_wizard_new_group_user access.dss.binaries.wizard.new model_dss_binaries_wizard_new base.group_user 1 1 1 1
56 digitalsignage_dss_linkmail_group_user access.dss.linkmail model_dss_linkmail base.group_user 1 1 1 1
57 digitalsignage_dss_kileads_requests access.dss.kileads.requests model_dss_kileads_requests base.group_user 1 1 1 1
58 digitalsignage_dss_kileads access.dss.kileads model_dss_kileads base.group_user 1 1 1 1
59 digitalsignage_dss_contracts_uservars_group_user access.dss.contracts_uservars model_dss_contracts_uservars base.group_user 1 1 1 1
60 digitalsignage_dss_settings_vars_group_user access.dss.settings.vars model_dss_settings_vars base.group_user 1 1 1 1

View File

@ -52,4 +52,10 @@ width:90px;
min-width: 30px !important;
}
.dss_form_line {
border-style: double;
border-width: 1px;
border-color:#B0B0B0
}

BIN
static/src/img/amazon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 KiB

BIN
static/src/img/joyn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
static/src/img/netflix.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g>
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M8 20v1.932a.5.5 0 0 1-.82.385l-4.12-3.433A.5.5 0 0 1 3.382 18H18a2 2 0 0 0 2-2V8h2v8a4 4 0 0 1-4 4H8zm8-16V2.068a.5.5 0 0 1 .82-.385l4.12 3.433a.5.5 0 0 1-.321.884H6a2 2 0 0 0-2 2v8H2V8a4 4 0 0 1 4-4h10zm-5 4h2v8h-2v-6H9V9l2-1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 529 B

BIN
static/src/img/waipu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

9
static/src/info.txt Normal file
View File

@ -0,0 +1,9 @@
; (function() {
ace.require(["ace/ext/error_marker"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,9 @@
; (function() {
ace.require(["ace/ext/error_marker"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,343 @@
ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator"], function(require, exports, module){/**
* ## Code beautification and formatting extension.
*
* **This extension is considered outdated.** For better formatting support with modern language servers
* and advanced formatting capabilities, consider using [ace-linters](https://github.com/mkslanc/ace-linters)
* which provides comprehensive language support including formatting, linting, and IntelliSense features.
*
* This legacy extension provides basic formatting for HTML, CSS, JavaScript, and PHP code with support for
* proper indentation, whitespace management, line breaks, and bracket alignment. It handles various language
* constructs including HTML tags, CSS selectors, JavaScript operators, control structures, and maintains
* consistent code style throughout the document.
*
* @module
*/
"use strict";
var TokenIterator = require("../token_iterator").TokenIterator;
function is(token, type) {
return token.type.lastIndexOf(type + ".xml") > -1;
}
exports.singletonTags = ["area", "base", "br", "col", "command", "embed", "hr", "html", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];
exports.blockTags = ["article", "aside", "blockquote", "body", "div", "dl", "fieldset", "footer", "form", "head", "header", "html", "nav", "ol", "p", "script", "section", "style", "table", "tbody", "tfoot", "thead", "ul"];
exports.formatOptions = {
lineBreaksAfterCommasInCurlyBlock: true
};
exports.beautify = function (session) {
var iterator = new TokenIterator(session, 0, 0);
var token = iterator.getCurrentToken();
var tabString = session.getTabString();
var singletonTags = exports.singletonTags;
var blockTags = exports.blockTags;
var formatOptions = exports.formatOptions || {};
var nextToken;
var breakBefore = false;
var spaceBefore = false;
var spaceAfter = false;
var code = "";
var value = "";
var tagName = "";
var depth = 0;
var lastDepth = 0;
var lastIndent = 0;
var indent = 0;
var unindent = 0;
var roundDepth = 0;
var curlyDepth = 0;
var row;
var curRow = 0;
var rowsToAdd = 0;
var rowTokens = [];
var abort = false;
var i;
var indentNextLine = false;
var inTag = false;
var inCSS = false;
var inBlock = false;
var levels = { 0: 0 };
var parents = [];
var caseBody = false;
var trimNext = function () {
if (nextToken && nextToken.value && nextToken.type !== 'string.regexp')
nextToken.value = nextToken.value.replace(/^\s*/, "");
};
var trimLine = function () {
var end = code.length - 1;
while (true) {
if (end == 0)
break;
if (code[end] !== " ")
break;
end = end - 1;
}
code = code.slice(0, end + 1);
};
var trimCode = function () {
code = code.trimRight();
breakBefore = false;
};
while (token !== null) {
curRow = iterator.getCurrentTokenRow();
rowTokens = iterator.$rowTokens;
nextToken = iterator.stepForward();
if (typeof token !== "undefined") {
value = token.value;
unindent = 0;
inCSS = (tagName === "style" || session.$modeId === "ace/mode/css");
if (is(token, "tag-open")) {
inTag = true;
if (nextToken)
inBlock = (blockTags.indexOf(nextToken.value) !== -1);
if (value === "</") {
if (inBlock && !breakBefore && rowsToAdd < 1)
rowsToAdd++;
if (inCSS)
rowsToAdd = 1;
unindent = 1;
inBlock = false;
}
}
else if (is(token, "tag-close")) {
inTag = false;
}
else if (is(token, "comment.start")) {
inBlock = true;
}
else if (is(token, "comment.end")) {
inBlock = false;
}
if (!inTag && !rowsToAdd && token.type === "paren.rparen" && token.value.substr(0, 1) === "}") {
rowsToAdd++;
}
if (curRow !== row) {
rowsToAdd = curRow;
if (row)
rowsToAdd -= row;
}
if (rowsToAdd) {
trimCode();
for (; rowsToAdd > 0; rowsToAdd--)
code += "\n";
breakBefore = true;
if (!is(token, "comment") && !token.type.match(/^(comment|string)$/))
value = value.trimLeft();
}
if (value) {
if (token.type === "keyword" && value.match(/^(if|else|elseif|for|foreach|while|switch)$/)) {
parents[depth] = value;
trimNext();
spaceAfter = true;
if (value.match(/^(else|elseif)$/)) {
if (code.match(/\}[\s]*$/)) {
trimCode();
spaceBefore = true;
}
}
}
else if (token.type === "paren.lparen") {
trimNext();
if (value.substr(-1) === "{") {
spaceAfter = true;
indentNextLine = false;
if (!inTag)
rowsToAdd = 1;
}
if (value.substr(0, 1) === "{") {
spaceBefore = true;
if (code.substr(-1) !== '[' && code.trimRight().substr(-1) === '[') {
trimCode();
spaceBefore = false;
}
else if (code.trimRight().substr(-1) === ')') {
trimCode();
}
else {
trimLine();
}
}
}
else if (token.type === "paren.rparen") {
unindent = 1;
if (value.substr(0, 1) === "}") {
if (parents[depth - 1] === 'case')
unindent++;
if (code.trimRight().substr(-1) === '{') {
trimCode();
}
else {
spaceBefore = true;
if (inCSS)
rowsToAdd += 2;
}
}
if (value.substr(0, 1) === "]") {
if (code.substr(-1) !== '}' && code.trimRight().substr(-1) === '}') {
spaceBefore = false;
indent++;
trimCode();
}
}
if (value.substr(0, 1) === ")") {
if (code.substr(-1) !== '(' && code.trimRight().substr(-1) === '(') {
spaceBefore = false;
indent++;
trimCode();
}
}
trimLine();
}
else if ((token.type === "keyword.operator" || token.type === "keyword") && value.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=|=>)$/)) {
trimCode();
trimNext();
spaceBefore = true;
spaceAfter = true;
}
else if (token.type === "punctuation.operator" && value === ';') {
trimCode();
trimNext();
spaceAfter = true;
if (inCSS)
rowsToAdd++;
}
else if (token.type === "punctuation.operator" && value.match(/^(:|,)$/)) {
trimCode();
trimNext();
if (value.match(/^(,)$/) && curlyDepth > 0 && roundDepth === 0 && formatOptions.lineBreaksAfterCommasInCurlyBlock) {
rowsToAdd++;
}
else {
spaceAfter = true;
breakBefore = false;
}
}
else if (token.type === "support.php_tag" && value === "?>" && !breakBefore) {
trimCode();
spaceBefore = true;
}
else if (is(token, "attribute-name") && code.substr(-1).match(/^\s$/)) {
spaceBefore = true;
}
else if (is(token, "attribute-equals")) {
trimLine();
trimNext();
}
else if (is(token, "tag-close")) {
trimLine();
if (value === "/>")
spaceBefore = true;
}
else if (token.type === "keyword" && value.match(/^(case|default)$/)) {
if (caseBody)
unindent = 1;
}
if (breakBefore && !(token.type.match(/^(comment)$/) && !value.substr(0, 1).match(/^[/#]$/)) && !(token.type.match(/^(string)$/) && !value.substr(0, 1).match(/^['"@]$/))) {
indent = lastIndent;
if (depth > lastDepth) {
indent++;
for (i = depth; i > lastDepth; i--)
levels[i] = indent;
}
else if (depth < lastDepth)
indent = levels[depth];
lastDepth = depth;
lastIndent = indent;
if (unindent)
indent -= unindent;
if (indentNextLine && !roundDepth) {
indent++;
indentNextLine = false;
}
for (i = 0; i < indent; i++)
code += tabString;
}
if (token.type === "keyword" && value.match(/^(case|default)$/)) {
if (caseBody === false) {
parents[depth] = value;
depth++;
caseBody = true;
}
}
else if (token.type === "keyword" && value.match(/^(break)$/)) {
if (parents[depth - 1] && parents[depth - 1].match(/^(case|default)$/)) {
depth--;
caseBody = false;
}
}
if (token.type === "paren.lparen") {
roundDepth += (value.match(/\(/g) || []).length;
curlyDepth += (value.match(/\{/g) || []).length;
depth += value.length;
}
if (token.type === "keyword" && value.match(/^(if|else|elseif|for|while)$/)) {
indentNextLine = true;
roundDepth = 0;
}
else if (!roundDepth && value.trim() && token.type !== "comment")
indentNextLine = false;
if (token.type === "paren.rparen") {
roundDepth -= (value.match(/\)/g) || []).length;
curlyDepth -= (value.match(/\}/g) || []).length;
for (i = 0; i < value.length; i++) {
depth--;
if (value.substr(i, 1) === '}' && parents[depth] === 'case') {
depth--;
}
}
}
if (token.type == "text")
value = value.replace(/\s+$/, " ");
if (spaceBefore && !breakBefore) {
trimLine();
if (code.substr(-1) !== "\n")
code += " ";
}
code += value;
if (spaceAfter)
code += " ";
breakBefore = false;
spaceBefore = false;
spaceAfter = false;
if ((is(token, "tag-close") && (inBlock || blockTags.indexOf(tagName) !== -1)) || (is(token, "doctype") && value === ">")) {
if (inBlock && nextToken && nextToken.value === "</")
rowsToAdd = -1;
else
rowsToAdd = 1;
}
if (nextToken && singletonTags.indexOf(nextToken.value) === -1) {
if (is(token, "tag-open") && value === "</") {
depth--;
}
else if (is(token, "tag-open") && value === "<") {
depth++;
}
else if (is(token, "tag-close") && value === "/>") {
depth--;
}
}
if (is(token, "tag-name")) {
tagName = value;
}
row = curRow;
}
}
token = nextToken;
}
code = code.trim();
session.doc.setValue(code);
};
exports.commands = [{
name: "beautify",
description: "Format selection (Beautify)",
exec: function (editor) {
exports.beautify(editor.session);
},
bindKey: "Ctrl-Shift-B"
}];
}); (function() {
ace.require(["ace/ext/beautify"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,204 @@
ace.define("ace/ext/code_lens",["require","exports","module","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/editor","ace/config"], function(require, exports, module){/**
* ## Code Lens extension.
*
* Displaying contextual information and clickable commands above code lines. Supports registering custom providers,
* rendering lens widgets with proper positioning and styling, and handling user interactions with lens commands.
* @module
*/
"use strict";
var event = require("../lib/event");
var lang = require("../lib/lang");
var dom = require("../lib/dom");
function clearLensElements(renderer) {
var textLayer = renderer.$textLayer;
var lensElements = textLayer.$lenses;
if (lensElements)
lensElements.forEach(function (el) { el.remove(); });
textLayer.$lenses = null;
}
function renderWidgets(changes, renderer) {
var changed = changes & renderer.CHANGE_LINES
|| changes & renderer.CHANGE_FULL
|| changes & renderer.CHANGE_SCROLL
|| changes & renderer.CHANGE_TEXT;
if (!changed)
return;
var session = renderer.session;
var lineWidgets = renderer.session.lineWidgets;
var textLayer = renderer.$textLayer;
var lensElements = textLayer.$lenses;
if (!lineWidgets) {
if (lensElements)
clearLensElements(renderer);
return;
}
var textCells = renderer.$textLayer.$lines.cells;
var config = renderer.layerConfig;
var padding = renderer.$padding;
if (!lensElements)
lensElements = textLayer.$lenses = [];
var index = 0;
for (var i = 0; i < textCells.length; i++) {
var row = textCells[i].row;
var widget = lineWidgets[row];
var lenses = widget && widget.lenses;
if (!lenses || !lenses.length)
continue;
var lensContainer = lensElements[index];
if (!lensContainer) {
lensContainer = lensElements[index]
= dom.buildDom(["div", { class: "ace_codeLens" }], renderer.container);
}
lensContainer.style.height = config.lineHeight + "px";
index++;
for (var j = 0; j < lenses.length; j++) {
var el = lensContainer.childNodes[2 * j];
if (!el) {
if (j != 0)
lensContainer.appendChild(dom.createTextNode("\xa0|\xa0"));
el = dom.buildDom(["a"], lensContainer);
}
el.textContent = lenses[j].title;
(el).lensCommand = lenses[j];
}
while (lensContainer.childNodes.length > 2 * j - 1)
lensContainer.lastChild.remove();
var top = renderer.$cursorLayer.getPixelPosition({
row: row,
column: 0
}, true).top - config.lineHeight * widget.rowsAbove - config.offset;
lensContainer.style.top = top + "px";
var left = renderer.gutterWidth;
var indent = session.getLine(row).search(/\S|$/);
if (indent == -1)
indent = 0;
left += indent * config.characterWidth;
lensContainer.style.paddingLeft = padding + left + "px";
}
while (index < lensElements.length)
lensElements.pop().remove();
}
function clearCodeLensWidgets(session) {
if (!session.lineWidgets)
return;
var widgetManager = session.widgetManager;
session.lineWidgets.forEach(function (widget) {
if (widget && widget.lenses)
widgetManager.removeLineWidget(widget);
});
}
exports.setLenses = function (session, lenses) {
var firstRow = Number.MAX_VALUE;
clearCodeLensWidgets(session);
lenses && lenses.forEach(function (lens) {
var row = lens.start.row;
var column = lens.start.column;
var widget = session.lineWidgets && session.lineWidgets[row];
if (!widget || !widget.lenses) {
widget = session.widgetManager.$registerLineWidget({
rowCount: 1,
rowsAbove: 1,
row: row,
column: column,
lenses: []
});
}
widget.lenses.push(lens.command);
if (row < firstRow)
firstRow = row;
});
session._emit("changeFold", { data: { start: { row: firstRow } } });
return firstRow;
};
function attachToEditor(editor) {
editor.codeLensProviders = [];
editor.renderer.on("afterRender", renderWidgets);
if (!editor.$codeLensClickHandler) {
editor.$codeLensClickHandler = function (e) {
var command = e.target.lensCommand;
if (!command)
return;
editor.execCommand(command.id, command.arguments);
editor._emit("codeLensClick", e);
};
event.addListener(editor.container, "click", editor.$codeLensClickHandler, editor);
}
editor.$updateLenses = function () {
var session = editor.session;
if (!session)
return;
var providersToWaitNum = editor.codeLensProviders.length;
var lenses = [];
editor.codeLensProviders.forEach(function (provider) {
provider.provideCodeLenses(session, function (err, payload) {
if (err)
return;
payload.forEach(function (lens) {
lenses.push(lens);
});
providersToWaitNum--;
if (providersToWaitNum == 0) {
applyLenses();
}
});
});
function applyLenses() {
var cursor = session.selection.cursor;
var oldRow = session.documentToScreenRow(cursor);
var scrollTop = session.getScrollTop();
var firstRow = exports.setLenses(session, lenses);
var lastDelta = session.$undoManager && session.$undoManager.$lastDelta;
if (lastDelta && lastDelta.action == "remove" && lastDelta.lines.length > 1)
return;
var row = session.documentToScreenRow(cursor);
var lineHeight = editor.renderer.layerConfig.lineHeight;
var top = session.getScrollTop() + (row - oldRow) * lineHeight;
if (firstRow == 0 && scrollTop < lineHeight / 4 && scrollTop > -lineHeight / 4) {
top = -lineHeight;
}
session.setScrollTop(top);
}
};
var updateLenses = lang.delayedCall(editor.$updateLenses);
editor.$updateLensesOnInput = function () {
updateLenses.delay(250);
};
editor.on("input", editor.$updateLensesOnInput);
}
function detachFromEditor(editor) {
editor.off("input", editor.$updateLensesOnInput);
editor.renderer.off("afterRender", renderWidgets);
if (editor.$codeLensClickHandler)
editor.container.removeEventListener("click", editor.$codeLensClickHandler);
}
exports.registerCodeLensProvider = function (editor, codeLensProvider) {
editor.setOption("enableCodeLens", true);
editor.codeLensProviders.push(codeLensProvider);
editor.$updateLensesOnInput();
};
exports.clear = function (session) {
exports.setLenses(session, null);
};
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
enableCodeLens: {
set: function (val) {
if (val) {
attachToEditor(this);
}
else {
detachFromEditor(this);
}
}
}
});
dom.importCssString("\n.ace_codeLens {\n position: absolute;\n color: #aaa;\n font-size: 88%;\n background: inherit;\n width: 100%;\n display: flex;\n align-items: flex-end;\n pointer-events: none;\n}\n.ace_codeLens > a {\n cursor: pointer;\n pointer-events: auto;\n}\n.ace_codeLens > a:hover {\n color: #0000ff;\n text-decoration: underline;\n}\n.ace_dark > .ace_codeLens > a:hover {\n color: #4e94ce;\n}\n", "codelense.css", false);
}); (function() {
ace.require(["ace/ext/code_lens"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,469 @@
ace.define("ace/ext/command_bar",["require","exports","module","ace/tooltip","ace/lib/event_emitter","ace/lib/lang","ace/lib/dom","ace/lib/oop","ace/lib/useragent"], function(require, exports, module){/**
* ## Command Bar extension.
*
* Provides an interactive command bar tooltip that displays above the editor's active line. The extension enables
* clickable commands with keyboard shortcuts, icons, and various button types including standard buttons, checkboxes,
* and text elements. Supports overflow handling with a secondary tooltip for additional commands when space is limited.
* The tooltip can be configured to always show or display only on mouse hover over the active line.
*
* @module
*/
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var Tooltip = require("../tooltip").Tooltip;
var EventEmitter = require("../lib/event_emitter").EventEmitter;
var lang = require("../lib/lang");
var dom = require("../lib/dom");
var oop = require("../lib/oop");
var useragent = require("../lib/useragent");
var BUTTON_CLASS_NAME = 'command_bar_tooltip_button';
var VALUE_CLASS_NAME = 'command_bar_button_value';
var CAPTION_CLASS_NAME = 'command_bar_button_caption';
var KEYBINDING_CLASS_NAME = 'command_bar_keybinding';
var TOOLTIP_CLASS_NAME = 'command_bar_tooltip';
var MORE_OPTIONS_BUTTON_ID = 'MoreOptionsButton';
var defaultDelay = 100;
var defaultMaxElements = 4;
var minPosition = function (posA, posB) {
if (posB.row > posA.row) {
return posA;
}
else if (posB.row === posA.row && posB.column > posA.column) {
return posA;
}
return posB;
};
var keyDisplayMap = {
"Ctrl": { mac: "^" },
"Option": { mac: "⌥" },
"Command": { mac: "⌘" },
"Cmd": { mac: "⌘" },
"Shift": "⇧",
"Left": "←",
"Right": "→",
"Up": "↑",
"Down": "↓"
};
var CommandBarTooltip = /** @class */ (function () {
function CommandBarTooltip(parentNode, options) {
var e_1, _a;
options = options || {};
this.parentNode = parentNode;
this.tooltip = new Tooltip(this.parentNode);
this.moreOptions = new Tooltip(this.parentNode);
this.maxElementsOnTooltip = options.maxElementsOnTooltip || defaultMaxElements;
this.$alwaysShow = options.alwaysShow || false;
this.eventListeners = {};
this.elements = {};
this.commands = {};
this.tooltipEl = dom.buildDom(['div', { class: TOOLTIP_CLASS_NAME }], this.tooltip.getElement());
this.moreOptionsEl = dom.buildDom(['div', { class: TOOLTIP_CLASS_NAME + " tooltip_more_options" }], this.moreOptions.getElement());
this.$showTooltipTimer = lang.delayedCall(this.$showTooltip.bind(this), options.showDelay || defaultDelay);
this.$hideTooltipTimer = lang.delayedCall(this.$hideTooltip.bind(this), options.hideDelay || defaultDelay);
this.$tooltipEnter = this.$tooltipEnter.bind(this);
this.$onMouseMove = this.$onMouseMove.bind(this);
this.$onChangeScroll = this.$onChangeScroll.bind(this);
this.$onEditorChangeSession = this.$onEditorChangeSession.bind(this);
this.$scheduleTooltipForHide = this.$scheduleTooltipForHide.bind(this);
this.$preventMouseEvent = this.$preventMouseEvent.bind(this);
try {
for (var _b = __values(["mousedown", "mouseup", "click"]), _c = _b.next(); !_c.done; _c = _b.next()) {
var event = _c.value;
this.tooltip.getElement().addEventListener(event, this.$preventMouseEvent);
this.moreOptions.getElement().addEventListener(event, this.$preventMouseEvent);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
}
CommandBarTooltip.prototype.registerCommand = function (id, command) {
var registerForMainTooltip = Object.keys(this.commands).length < this.maxElementsOnTooltip;
if (!registerForMainTooltip && !this.elements[MORE_OPTIONS_BUTTON_ID]) {
this.$createCommand(MORE_OPTIONS_BUTTON_ID, {
name: "···",
exec:
function () {
this.$shouldHideMoreOptions = false;
this.$setMoreOptionsVisibility(!this.isMoreOptionsShown());
}.bind(this),
type: "checkbox",
getValue: function () {
return this.isMoreOptionsShown();
}.bind(this),
enabled: true
}, true);
}
this.$createCommand(id, command, registerForMainTooltip);
if (this.isShown()) {
this.updatePosition();
}
};
CommandBarTooltip.prototype.isShown = function () {
return !!this.tooltip && this.tooltip.isOpen;
};
CommandBarTooltip.prototype.isMoreOptionsShown = function () {
return !!this.moreOptions && this.moreOptions.isOpen;
};
CommandBarTooltip.prototype.getAlwaysShow = function () {
return this.$alwaysShow;
};
CommandBarTooltip.prototype.setAlwaysShow = function (alwaysShow) {
this.$alwaysShow = alwaysShow;
this.$updateOnHoverHandlers(!this.$alwaysShow);
this._signal("alwaysShow", this.$alwaysShow);
};
CommandBarTooltip.prototype.attach = function (editor) {
if (!editor || (this.isShown() && this.editor === editor)) {
return;
}
this.detach();
this.editor = editor;
this.editor.on("changeSession", this.$onEditorChangeSession);
if (this.editor.session) {
this.editor.session.on("changeScrollLeft", this.$onChangeScroll);
this.editor.session.on("changeScrollTop", this.$onChangeScroll);
}
if (this.getAlwaysShow()) {
this.$showTooltip();
}
else {
this.$updateOnHoverHandlers(true);
}
};
CommandBarTooltip.prototype.updatePosition = function () {
if (!this.editor) {
return;
}
var renderer = this.editor.renderer;
var ranges;
if (this.editor.selection.getAllRanges) {
ranges = this.editor.selection.getAllRanges();
}
else {
ranges = [this.editor.getSelectionRange()];
}
if (!ranges.length) {
return;
}
var minPos = minPosition(ranges[0].start, ranges[0].end);
for (var i = 0, range; range = ranges[i]; i++) {
minPos = minPosition(minPos, minPosition(range.start, range.end));
}
var pos = renderer.$cursorLayer.getPixelPosition(minPos, true);
var tooltipEl = this.tooltip.getElement();
var screenWidth = window.innerWidth;
var screenHeight = window.innerHeight;
var rect = this.editor.container.getBoundingClientRect();
pos.top += rect.top - renderer.layerConfig.offset;
pos.left += rect.left + renderer.gutterWidth - renderer.scrollLeft;
var cursorVisible = pos.top >= rect.top && pos.top <= rect.bottom &&
pos.left >= rect.left + renderer.gutterWidth && pos.left <= rect.right;
if (!cursorVisible && this.isShown()) {
this.$hideTooltip();
return;
}
else if (cursorVisible && !this.isShown() && this.getAlwaysShow()) {
this.$showTooltip();
return;
}
var top = pos.top - tooltipEl.offsetHeight;
var left = Math.min(screenWidth - tooltipEl.offsetWidth, pos.left);
var tooltipFits = top >= 0 && top + tooltipEl.offsetHeight <= screenHeight &&
left >= 0 && left + tooltipEl.offsetWidth <= screenWidth;
if (!tooltipFits) {
this.$hideTooltip();
return;
}
this.tooltip.setPosition(left, top);
if (this.isMoreOptionsShown()) {
top = top + tooltipEl.offsetHeight;
left = this.elements[MORE_OPTIONS_BUTTON_ID].getBoundingClientRect().left;
var moreOptionsEl = this.moreOptions.getElement();
var screenHeight = window.innerHeight;
if (top + moreOptionsEl.offsetHeight > screenHeight) {
top -= tooltipEl.offsetHeight + moreOptionsEl.offsetHeight;
}
if (left + moreOptionsEl.offsetWidth > screenWidth) {
left = screenWidth - moreOptionsEl.offsetWidth;
}
this.moreOptions.setPosition(left, top);
}
};
CommandBarTooltip.prototype.update = function () {
Object.keys(this.elements).forEach(this.$updateElement.bind(this));
};
CommandBarTooltip.prototype.detach = function () {
this.tooltip.hide();
this.moreOptions.hide();
this.$updateOnHoverHandlers(false);
if (this.editor) {
this.editor.off("changeSession", this.$onEditorChangeSession);
if (this.editor.session) {
this.editor.session.off("changeScrollLeft", this.$onChangeScroll);
this.editor.session.off("changeScrollTop", this.$onChangeScroll);
}
}
this.$mouseInTooltip = false;
this.editor = null;
};
CommandBarTooltip.prototype.destroy = function () {
if (this.tooltip && this.moreOptions) {
this.detach();
this.tooltip.destroy();
this.moreOptions.destroy();
}
this.eventListeners = {};
this.commands = {};
this.elements = {};
this.tooltip = this.moreOptions = this.parentNode = null;
};
CommandBarTooltip.prototype.$createCommand = function (id, command, forMainTooltip) {
var parentEl = forMainTooltip ? this.tooltipEl : this.moreOptionsEl;
var keyParts = [];
var bindKey = command.bindKey;
if (bindKey) {
if (typeof bindKey === 'object') {
bindKey = useragent.isMac ? bindKey.mac : bindKey.win;
}
bindKey = bindKey.split("|")[0];
keyParts = bindKey.split("-");
keyParts = keyParts.map(function (key) {
if (keyDisplayMap[key]) {
if (typeof keyDisplayMap[key] === 'string') {
return keyDisplayMap[key];
}
else if (useragent.isMac && keyDisplayMap[key].mac) {
return keyDisplayMap[key].mac;
}
}
return key;
});
}
var buttonNode;
if (forMainTooltip && command.iconCssClass) {
buttonNode = [
'div',
{
class: ["ace_icon_svg", command.iconCssClass].join(" "),
"aria-label": command.name + " (" + command.bindKey + ")"
}
];
}
else {
buttonNode = [
['div', { class: VALUE_CLASS_NAME }],
['div', { class: CAPTION_CLASS_NAME }, command.name]
];
if (keyParts.length) {
buttonNode.push([
'div',
{ class: KEYBINDING_CLASS_NAME },
keyParts.map(function (keyPart) {
return ['div', keyPart];
})
]);
}
}
dom.buildDom(['div', { class: [BUTTON_CLASS_NAME, command.cssClass || ""].join(" "), ref: id }, buttonNode], parentEl, this.elements);
this.commands[id] = command;
var eventListener =
function (e) {
if (this.editor) {
this.editor.focus();
}
this.$shouldHideMoreOptions = this.isMoreOptionsShown();
if (!this.elements[id].disabled && command.exec) {
command.exec(this.editor);
}
if (this.$shouldHideMoreOptions) {
this.$setMoreOptionsVisibility(false);
}
this.update();
e.preventDefault();
}.bind(this);
this.eventListeners[id] = eventListener;
this.elements[id].addEventListener('click', eventListener.bind(this));
this.$updateElement(id);
};
CommandBarTooltip.prototype.$setMoreOptionsVisibility = function (visible) {
if (visible) {
this.moreOptions.setTheme(this.editor.renderer.theme);
this.moreOptions.setClassName(TOOLTIP_CLASS_NAME + "_wrapper");
this.moreOptions.show();
this.update();
this.updatePosition();
}
else {
this.moreOptions.hide();
}
};
CommandBarTooltip.prototype.$onEditorChangeSession = function (e) {
if (e.oldSession) {
e.oldSession.off("changeScrollTop", this.$onChangeScroll);
e.oldSession.off("changeScrollLeft", this.$onChangeScroll);
}
this.detach();
};
CommandBarTooltip.prototype.$onChangeScroll = function () {
if (this.editor.renderer && (this.isShown() || this.getAlwaysShow())) {
this.editor.renderer.once("afterRender", this.updatePosition.bind(this));
}
};
CommandBarTooltip.prototype.$onMouseMove = function (e) {
if (this.$mouseInTooltip) {
return;
}
var cursorPosition = this.editor.getCursorPosition();
var cursorScreenPosition = this.editor.renderer.textToScreenCoordinates(cursorPosition.row, cursorPosition.column);
var lineHeight = this.editor.renderer.lineHeight;
var isInCurrentLine = e.clientY >= cursorScreenPosition.pageY && e.clientY < cursorScreenPosition.pageY + lineHeight;
if (isInCurrentLine) {
if (!this.isShown() && !this.$showTooltipTimer.isPending()) {
this.$showTooltipTimer.delay();
}
if (this.$hideTooltipTimer.isPending()) {
this.$hideTooltipTimer.cancel();
}
}
else {
if (this.isShown() && !this.$hideTooltipTimer.isPending()) {
this.$hideTooltipTimer.delay();
}
if (this.$showTooltipTimer.isPending()) {
this.$showTooltipTimer.cancel();
}
}
};
CommandBarTooltip.prototype.$preventMouseEvent = function (e) {
if (this.editor) {
this.editor.focus();
}
e.preventDefault();
};
CommandBarTooltip.prototype.$scheduleTooltipForHide = function () {
this.$mouseInTooltip = false;
this.$showTooltipTimer.cancel();
this.$hideTooltipTimer.delay();
};
CommandBarTooltip.prototype.$tooltipEnter = function () {
this.$mouseInTooltip = true;
if (this.$showTooltipTimer.isPending()) {
this.$showTooltipTimer.cancel();
}
if (this.$hideTooltipTimer.isPending()) {
this.$hideTooltipTimer.cancel();
}
};
CommandBarTooltip.prototype.$updateOnHoverHandlers = function (enableHover) {
var tooltipEl = this.tooltip.getElement();
var moreOptionsEl = this.moreOptions.getElement();
if (enableHover) {
if (this.editor) {
this.editor.on("mousemove", this.$onMouseMove);
this.editor.renderer.getMouseEventTarget().addEventListener("mouseout", this.$scheduleTooltipForHide, true);
}
tooltipEl.addEventListener('mouseenter', this.$tooltipEnter);
tooltipEl.addEventListener('mouseleave', this.$scheduleTooltipForHide);
moreOptionsEl.addEventListener('mouseenter', this.$tooltipEnter);
moreOptionsEl.addEventListener('mouseleave', this.$scheduleTooltipForHide);
}
else {
if (this.editor) {
this.editor.off("mousemove", this.$onMouseMove);
this.editor.renderer.getMouseEventTarget().removeEventListener("mouseout", this.$scheduleTooltipForHide, true);
}
tooltipEl.removeEventListener('mouseenter', this.$tooltipEnter);
tooltipEl.removeEventListener('mouseleave', this.$scheduleTooltipForHide);
moreOptionsEl.removeEventListener('mouseenter', this.$tooltipEnter);
moreOptionsEl.removeEventListener('mouseleave', this.$scheduleTooltipForHide);
}
};
CommandBarTooltip.prototype.$showTooltip = function () {
if (this.isShown()) {
return;
}
this.tooltip.setTheme(this.editor.renderer.theme);
this.tooltip.setClassName(TOOLTIP_CLASS_NAME + "_wrapper");
this.tooltip.show();
this.update();
this.updatePosition();
this._signal("show");
};
CommandBarTooltip.prototype.$hideTooltip = function () {
this.$mouseInTooltip = false;
if (!this.isShown()) {
return;
}
this.moreOptions.hide();
this.tooltip.hide();
this._signal("hide");
};
CommandBarTooltip.prototype.$updateElement = function (id) {
var command = this.commands[id];
if (!command) {
return;
}
var el = this.elements[id];
var commandEnabled = command.enabled;
if (typeof commandEnabled === 'function') {
commandEnabled = commandEnabled(this.editor);
}
if (typeof command.getValue === 'function') {
var value = command.getValue(this.editor);
if (command.type === 'text') {
el.textContent = value;
}
else if (command.type === 'checkbox') {
var domCssFn = value ? dom.addCssClass : dom.removeCssClass;
var isOnTooltip = el.parentElement === this.tooltipEl;
el.ariaChecked = value;
if (isOnTooltip) {
domCssFn(el, "ace_selected");
}
else {
el = el.querySelector("." + VALUE_CLASS_NAME);
domCssFn(el, "ace_checkmark");
}
}
}
if (commandEnabled && el.disabled) {
dom.removeCssClass(el, "ace_disabled");
el.ariaDisabled = el.disabled = false;
el.removeAttribute("disabled");
}
else if (!commandEnabled && !el.disabled) {
dom.addCssClass(el, "ace_disabled");
el.ariaDisabled = el.disabled = true;
el.setAttribute("disabled", "");
}
};
return CommandBarTooltip;
}());
oop.implement(CommandBarTooltip.prototype, EventEmitter);
dom.importCssString("\n.ace_tooltip.".concat(TOOLTIP_CLASS_NAME, "_wrapper {\n padding: 0;\n}\n\n.ace_tooltip .").concat(TOOLTIP_CLASS_NAME, " {\n padding: 1px 5px;\n display: flex;\n pointer-events: auto;\n}\n\n.ace_tooltip .").concat(TOOLTIP_CLASS_NAME, ".tooltip_more_options {\n padding: 1px;\n flex-direction: column;\n}\n\ndiv.").concat(BUTTON_CLASS_NAME, " {\n display: inline-flex;\n cursor: pointer;\n margin: 1px;\n border-radius: 2px;\n padding: 2px 5px;\n align-items: center;\n}\n\ndiv.").concat(BUTTON_CLASS_NAME, ".ace_selected,\ndiv.").concat(BUTTON_CLASS_NAME, ":hover:not(.ace_disabled) {\n background-color: rgba(0, 0, 0, 0.1);\n}\n\ndiv.").concat(BUTTON_CLASS_NAME, ".ace_disabled {\n color: #777;\n pointer-events: none;\n}\n\ndiv.").concat(BUTTON_CLASS_NAME, " .ace_icon_svg {\n height: 12px;\n background-color: #000;\n}\n\ndiv.").concat(BUTTON_CLASS_NAME, ".ace_disabled .ace_icon_svg {\n background-color: #777;\n}\n\n.").concat(TOOLTIP_CLASS_NAME, ".tooltip_more_options .").concat(BUTTON_CLASS_NAME, " {\n display: flex;\n}\n\n.").concat(TOOLTIP_CLASS_NAME, ".").concat(VALUE_CLASS_NAME, " {\n display: none;\n}\n\n.").concat(TOOLTIP_CLASS_NAME, ".tooltip_more_options .").concat(VALUE_CLASS_NAME, " {\n display: inline-block;\n width: 12px;\n}\n\n.").concat(CAPTION_CLASS_NAME, " {\n display: inline-block;\n}\n\n.").concat(KEYBINDING_CLASS_NAME, " {\n margin: 0 2px;\n display: inline-block;\n font-size: 8px;\n}\n\n.").concat(TOOLTIP_CLASS_NAME, ".tooltip_more_options .").concat(KEYBINDING_CLASS_NAME, " {\n margin-left: auto;\n}\n\n.").concat(KEYBINDING_CLASS_NAME, " div {\n display: inline-block;\n min-width: 8px;\n padding: 2px;\n margin: 0 1px;\n border-radius: 2px;\n background-color: #ccc;\n text-align: center;\n}\n\n.ace_dark.ace_tooltip .").concat(TOOLTIP_CLASS_NAME, " {\n background-color: #373737;\n color: #eee;\n}\n\n.ace_dark div.").concat(BUTTON_CLASS_NAME, ".ace_disabled {\n color: #979797;\n}\n\n.ace_dark div.").concat(BUTTON_CLASS_NAME, ".ace_selected,\n.ace_dark div.").concat(BUTTON_CLASS_NAME, ":hover:not(.ace_disabled) {\n background-color: rgba(255, 255, 255, 0.1);\n}\n\n.ace_dark div.").concat(BUTTON_CLASS_NAME, " .ace_icon_svg {\n background-color: #eee;\n}\n\n.ace_dark div.").concat(BUTTON_CLASS_NAME, ".ace_disabled .ace_icon_svg {\n background-color: #979797;\n}\n\n.ace_dark .").concat(BUTTON_CLASS_NAME, ".ace_disabled {\n color: #979797;\n}\n\n.ace_dark .").concat(KEYBINDING_CLASS_NAME, " div {\n background-color: #575757;\n}\n\n.ace_checkmark::before {\n content: '\u2713';\n}\n"), "commandbar.css", false);
exports.CommandBarTooltip = CommandBarTooltip;
exports.TOOLTIP_CLASS_NAME = TOOLTIP_CLASS_NAME;
exports.BUTTON_CLASS_NAME = BUTTON_CLASS_NAME;
}); (function() {
ace.require(["ace/ext/command_bar"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,238 @@
ace.define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"], function(require, exports, module){/**
* ## Elastic Tabstops Lite extension.
*
* Automatically adjusts tab spacing to align content in tabular format by calculating optimal column widths
* and maintaining consistent vertical alignment across multiple lines. Tracks content changes and dynamically
* reprocesses affected rows to ensure proper formatting without manual intervention.
*
* **Enable:** `editor.setOption("useElasticTabstops", true)`
* or configure it during editor initialization in the options object.
* @module
*/
"use strict";
var ElasticTabstopsLite = /** @class */ (function () {
function ElasticTabstopsLite(editor) {
this.$editor = editor;
var self = this;
var changedRows = [];
var recordChanges = false;
this.onAfterExec = function () {
recordChanges = false;
self.processRows(changedRows);
changedRows = [];
};
this.onExec = function () {
recordChanges = true;
};
this.onChange = function (delta) {
if (recordChanges) {
if (changedRows.indexOf(delta.start.row) == -1)
changedRows.push(delta.start.row);
if (delta.end.row != delta.start.row)
changedRows.push(delta.end.row);
}
};
}
ElasticTabstopsLite.prototype.processRows = function (rows) {
this.$inChange = true;
var checkedRows = [];
for (var r = 0, rowCount = rows.length; r < rowCount; r++) {
var row = rows[r];
if (checkedRows.indexOf(row) > -1)
continue;
var cellWidthObj = this.$findCellWidthsForBlock(row);
var cellWidths = this.$setBlockCellWidthsToMax(cellWidthObj.cellWidths);
var rowIndex = cellWidthObj.firstRow;
for (var w = 0, l = cellWidths.length; w < l; w++) {
var widths = cellWidths[w];
checkedRows.push(rowIndex);
this.$adjustRow(rowIndex, widths);
rowIndex++;
}
}
this.$inChange = false;
};
ElasticTabstopsLite.prototype.$findCellWidthsForBlock = function (row) {
var cellWidths = [], widths;
var rowIter = row;
while (rowIter >= 0) {
widths = this.$cellWidthsForRow(rowIter);
if (widths.length == 0)
break;
cellWidths.unshift(widths);
rowIter--;
}
var firstRow = rowIter + 1;
rowIter = row;
var numRows = this.$editor.session.getLength();
while (rowIter < numRows - 1) {
rowIter++;
widths = this.$cellWidthsForRow(rowIter);
if (widths.length == 0)
break;
cellWidths.push(widths);
}
return { cellWidths: cellWidths, firstRow: firstRow };
};
ElasticTabstopsLite.prototype.$cellWidthsForRow = function (row) {
var selectionColumns = this.$selectionColumnsForRow(row);
var tabs = [-1].concat(this.$tabsForRow(row));
var widths = tabs.map(function (el) { return 0; }).slice(1);
var line = this.$editor.session.getLine(row);
for (var i = 0, len = tabs.length - 1; i < len; i++) {
var leftEdge = tabs[i] + 1;
var rightEdge = tabs[i + 1];
var rightmostSelection = this.$rightmostSelectionInCell(selectionColumns, rightEdge);
var cell = line.substring(leftEdge, rightEdge);
widths[i] = Math.max(cell.replace(/\s+$/g, '').length, rightmostSelection - leftEdge);
}
return widths;
};
ElasticTabstopsLite.prototype.$selectionColumnsForRow = function (row) {
var selections = [], cursor = this.$editor.getCursorPosition();
if (this.$editor.session.getSelection().isEmpty()) {
if (row == cursor.row)
selections.push(cursor.column);
}
return selections;
};
ElasticTabstopsLite.prototype.$setBlockCellWidthsToMax = function (cellWidths) {
var startingNewBlock = true, blockStartRow, blockEndRow, maxWidth;
var columnInfo = this.$izip_longest(cellWidths);
for (var c = 0, l = columnInfo.length; c < l; c++) {
var column = columnInfo[c];
if (!column.push) {
console.error(column);
continue;
}
column.push(NaN);
for (var r = 0, s = column.length; r < s; r++) {
var width = column[r];
if (startingNewBlock) {
blockStartRow = r;
maxWidth = 0;
startingNewBlock = false;
}
if (isNaN(width)) {
blockEndRow = r;
for (var j = blockStartRow; j < blockEndRow; j++) {
cellWidths[j][c] = maxWidth;
}
startingNewBlock = true;
}
maxWidth = Math.max(maxWidth, width);
}
}
return cellWidths;
};
ElasticTabstopsLite.prototype.$rightmostSelectionInCell = function (selectionColumns, cellRightEdge) {
var rightmost = 0;
if (selectionColumns.length) {
var lengths = [];
for (var s = 0, length = selectionColumns.length; s < length; s++) {
if (selectionColumns[s] <= cellRightEdge)
lengths.push(s);
else
lengths.push(0);
}
rightmost = Math.max.apply(Math, lengths);
}
return rightmost;
};
ElasticTabstopsLite.prototype.$tabsForRow = function (row) {
var rowTabs = [], line = this.$editor.session.getLine(row), re = /\t/g, match;
while ((match = re.exec(line)) != null) {
rowTabs.push(match.index);
}
return rowTabs;
};
ElasticTabstopsLite.prototype.$adjustRow = function (row, widths) {
var rowTabs = this.$tabsForRow(row);
if (rowTabs.length == 0)
return;
var bias = 0, location = -1;
var expandedSet = this.$izip(widths, rowTabs);
for (var i = 0, l = expandedSet.length; i < l; i++) {
var w = expandedSet[i][0], it = expandedSet[i][1];
location += 1 + w;
it += bias;
var difference = location - it;
if (difference == 0)
continue;
var partialLine = this.$editor.session.getLine(row).substr(0, it);
var strippedPartialLine = partialLine.replace(/\s*$/g, "");
var ispaces = partialLine.length - strippedPartialLine.length;
if (difference > 0) {
this.$editor.session.getDocument().insertInLine({ row: row, column: it + 1 }, Array(difference + 1).join(" ") + "\t");
this.$editor.session.getDocument().removeInLine(row, it, it + 1);
bias += difference;
}
if (difference < 0 && ispaces >= -difference) {
this.$editor.session.getDocument().removeInLine(row, it + difference, it);
bias += difference;
}
}
};
ElasticTabstopsLite.prototype.$izip_longest = function (iterables) {
if (!iterables[0])
return [];
var longest = iterables[0].length;
var iterablesLength = iterables.length;
for (var i = 1; i < iterablesLength; i++) {
var iLength = iterables[i].length;
if (iLength > longest)
longest = iLength;
}
var expandedSet = [];
for (var l = 0; l < longest; l++) {
var set = [];
for (var i = 0; i < iterablesLength; i++) {
if (iterables[i][l] === "")
set.push(NaN);
else
set.push(iterables[i][l]);
}
expandedSet.push(set);
}
return expandedSet;
};
ElasticTabstopsLite.prototype.$izip = function (widths, tabs) {
var size = widths.length >= tabs.length ? tabs.length : widths.length;
var expandedSet = [];
for (var i = 0; i < size; i++) {
var set = [widths[i], tabs[i]];
expandedSet.push(set);
}
return expandedSet;
};
return ElasticTabstopsLite;
}());
exports.ElasticTabstopsLite = ElasticTabstopsLite;
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
useElasticTabstops: {
set: function (val) {
if (val) {
if (!this.elasticTabstops)
this.elasticTabstops = new ElasticTabstopsLite(this);
this.commands.on("afterExec", this.elasticTabstops.onAfterExec);
this.commands.on("exec", this.elasticTabstops.onExec);
this.on("change", this.elasticTabstops.onChange);
}
else if (this.elasticTabstops) {
this.commands.removeListener("afterExec", this.elasticTabstops.onAfterExec);
this.commands.removeListener("exec", this.elasticTabstops.onExec);
this.removeListener("change", this.elasticTabstops.onChange);
}
}
}
});
}); (function() {
ace.require(["ace/ext/elastic_tabstops_lite"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
; (function() {
ace.require(["ace/ext/error_marker"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,127 @@
ace.define("ace/ext/hardwrap",["require","exports","module","ace/range","ace/editor","ace/config"], function(require, exports, module){/**
* ## Text hard wrapping extension for automatic line breaking and text formatting.
*
* Provides intelligent line wrapping functionality that breaks long lines at configurable column limits while
* preserving indentation and optionally merging short adjacent lines. Supports both automatic wrapping during text
* input and manual formatting of selected text ranges.
*
* **Enable:** `editor.setOption("hardWrap", true)`
* or configure it during editor initialization in the options object.
* @module
*/
"use strict";
var Range = require("../range").Range;
function hardWrap(editor, options) {
var max = options.column || editor.getOption("printMarginColumn");
var allowMerge = options.allowMerge != false;
var row = Math.min(options.startRow, options.endRow);
var endRow = Math.max(options.startRow, options.endRow);
var session = editor.session;
while (row <= endRow) {
var line = session.getLine(row);
if (line.length > max) {
var space = findSpace(line, max, 5);
if (space) {
var indentation = /^\s*/.exec(line)[0];
session.replace(new Range(row, space.start, row, space.end), "\n" + indentation);
}
endRow++;
}
else if (allowMerge && /\S/.test(line) && row != endRow) {
var nextLine = session.getLine(row + 1);
if (nextLine && /\S/.test(nextLine)) {
var trimmedLine = line.replace(/\s+$/, "");
var trimmedNextLine = nextLine.replace(/^\s+/, "");
var mergedLine = trimmedLine + " " + trimmedNextLine;
var space = findSpace(mergedLine, max, 5);
if (space && space.start > trimmedLine.length || mergedLine.length < max) {
var replaceRange = new Range(row, trimmedLine.length, row + 1, nextLine.length - trimmedNextLine.length);
session.replace(replaceRange, " ");
row--;
endRow--;
}
else if (trimmedLine.length < line.length) {
session.remove(new Range(row, trimmedLine.length, row, line.length));
}
}
}
row++;
}
function findSpace(line, max, min) {
if (line.length < max)
return;
var before = line.slice(0, max);
var after = line.slice(max);
var spaceAfter = /^(?:(\s+)|(\S+)(\s+))/.exec(after);
var spaceBefore = /(?:(\s+)|(\s+)(\S+))$/.exec(before);
var start = 0;
var end = 0;
if (spaceBefore && !spaceBefore[2]) {
start = max - spaceBefore[1].length;
end = max;
}
if (spaceAfter && !spaceAfter[2]) {
if (!start)
start = max;
end = max + spaceAfter[1].length;
}
if (start) {
return {
start: start,
end: end
};
}
if (spaceBefore && spaceBefore[2] && spaceBefore.index > min) {
return {
start: spaceBefore.index,
end: spaceBefore.index + spaceBefore[2].length
};
}
if (spaceAfter && spaceAfter[2]) {
start = max + spaceAfter[2].length;
return {
start: start,
end: start + spaceAfter[3].length
};
}
}
}
function wrapAfterInput(e) {
if (e.command.name == "insertstring" && /\S/.test(e.args)) {
var editor = e.editor;
var cursor = editor.selection.cursor;
if (cursor.column <= editor.renderer.$printMarginColumn)
return;
var lastDelta = editor.session.$undoManager.$lastDelta;
hardWrap(editor, {
startRow: cursor.row, endRow: cursor.row,
allowMerge: false
});
if (lastDelta != editor.session.$undoManager.$lastDelta)
editor.session.markUndoGroup();
}
}
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
hardWrap: {
set: function (val) {
if (val) {
this.commands.on("afterExec", wrapAfterInput);
}
else {
this.commands.off("afterExec", wrapAfterInput);
}
},
value: false
}
});
exports.hardWrap = hardWrap;
}); (function() {
ace.require(["ace/ext/hardwrap"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,185 @@
ace.define("ace/ext/menu_tools/settings_menu.css",["require","exports","module"], function(require, exports, module){module.exports = "#ace_settingsmenu, #kbshortcutmenu {\n background-color: #F7F7F7;\n color: black;\n box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);\n padding: 1em 0.5em 2em 1em;\n overflow: auto;\n position: absolute;\n margin: 0;\n bottom: 0;\n right: 0;\n top: 0;\n z-index: 9991;\n cursor: default;\n}\n\n.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {\n box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);\n background-color: rgba(255, 255, 255, 0.6);\n color: black;\n}\n\n.ace_optionsMenuEntry:hover {\n background-color: rgba(100, 100, 100, 0.1);\n transition: all 0.3s\n}\n\n.ace_closeButton {\n background: rgba(245, 146, 146, 0.5);\n border: 1px solid #F48A8A;\n border-radius: 50%;\n padding: 7px;\n position: absolute;\n right: -8px;\n top: -8px;\n z-index: 100000;\n}\n.ace_closeButton{\n background: rgba(245, 146, 146, 0.9);\n}\n.ace_optionsMenuKey {\n color: darkslateblue;\n font-weight: bold;\n}\n.ace_optionsMenuCommand {\n color: darkcyan;\n font-weight: normal;\n}\n.ace_optionsMenuEntry input, .ace_optionsMenuEntry button {\n vertical-align: middle;\n}\n\n.ace_optionsMenuEntry button[ace_selected_button=true] {\n background: #e7e7e7;\n box-shadow: 1px 0px 2px 0px #adadad inset;\n border-color: #adadad;\n}\n.ace_optionsMenuEntry button {\n background: white;\n border: 1px solid lightgray;\n margin: 0px;\n}\n.ace_optionsMenuEntry button:hover{\n background: #f0f0f0;\n}";
});
ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/ext/menu_tools/overlay_page","ace/lib/dom","ace/ext/menu_tools/settings_menu.css"], function(require, exports, module){/**
* ## Overlay Page utility
*
* Provides modal overlay functionality for displaying editor extension interfaces. Creates a full-screen overlay with
* configurable backdrop behavior, keyboard navigation (ESC to close), and focus management. Used by various extensions
* to display menus, settings panels, and other interactive content over the editor interface.
*
* **Usage:**
* ```javascript
* var overlayPage = require('./overlay_page').overlayPage;
* var contentElement = document.createElement('div');
* contentElement.innerHTML = '<h1>Settings</h1>';
*
* var overlay = overlayPage(editor, contentElement, function() {
* console.log('Overlay closed');
* });
* ```
*
* @module
*/
'use strict';
var dom = require("../../lib/dom");
var cssText = require("./settings_menu.css");
dom.importCssString(cssText, "settings_menu.css", false);
module.exports.overlayPage = function overlayPage(editor, contentElement, callback) {
var closer = document.createElement('div');
var ignoreFocusOut = false;
function documentEscListener(e) {
if (e.keyCode === 27) {
close();
}
}
function close() {
if (!closer)
return;
document.removeEventListener('keydown', documentEscListener);
closer.parentNode.removeChild(closer);
if (editor) {
editor.focus();
}
closer = null;
callback && callback();
}
function setIgnoreFocusOut(ignore) {
ignoreFocusOut = ignore;
if (ignore) {
closer.style.pointerEvents = "none";
contentElement.style.pointerEvents = "auto";
}
}
closer.style.cssText = 'margin: 0; padding: 0; ' +
'position: fixed; top:0; bottom:0; left:0; right:0;' +
'z-index: 9990; ' +
(editor ? 'background-color: rgba(0, 0, 0, 0.3);' : '');
closer.addEventListener('click', function (e) {
if (!ignoreFocusOut) {
close();
}
});
document.addEventListener('keydown', documentEscListener);
contentElement.addEventListener('click', function (e) {
e.stopPropagation();
});
closer.appendChild(contentElement);
document.body.appendChild(closer);
if (editor) {
editor.blur();
}
return {
close: close,
setIgnoreFocusOut: setIgnoreFocusOut
};
};
});
ace.define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/ext/menu_tools/get_editor_keyboard_shortcuts","ace/lib/keys"], function(require, exports, module){/**
* ## Editor Keyboard Shortcuts Utility
*
* Provides functionality to extract and format keyboard shortcuts from an Ace editor instance. Analyzes all registered
* command handlers and their key bindings to generate a list of available keyboard shortcuts for the
* current platform. Returns formatted key combinations with proper modifier key representations and handles multiple
* bindings per command with pipe-separated notation.
*
* **Usage:**
* ```javascript
* var getKbShortcuts = require('ace/ext/menu_tools/get_editor_keyboard_shortcuts');
* var shortcuts = getKbShortcuts.getEditorKeybordShortcuts(editor);
* console.log(shortcuts);
* // [
* // {'command': 'selectall', 'key': 'Ctrl-A'},
* // {'command': 'copy', 'key': 'Ctrl-C|Ctrl-Insert'}
* // ]
* ```
*
* @module
*/
"use strict"; var keys = require("../../lib/keys");
module.exports.getEditorKeybordShortcuts = function (editor) {
var KEY_MODS = keys.KEY_MODS;
var keybindings = [];
var commandMap = {};
editor.keyBinding.$handlers.forEach(function (handler) {
var ckb = handler["commandKeyBinding"];
for (var i in ckb) {
var key = i.replace(/(^|-)\w/g, function (x) { return x.toUpperCase(); });
var commands = ckb[i];
if (!Array.isArray(commands))
commands = [commands];
commands.forEach(function (command) {
if (typeof command != "string")
command = command.name;
if (commandMap[command]) {
commandMap[command].key += "|" + key;
}
else {
commandMap[command] = { key: key, command: command };
keybindings.push(commandMap[command]);
}
});
}
});
return keybindings;
};
});
ace.define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"], function(require, exports, module){/**
* ## Show Keyboard Shortcuts extension
*
* Provides a keyboard shortcuts display overlay for the Ace editor. Creates an interactive menu that shows all available
* keyboard shortcuts with their corresponding commands, organized in a searchable and navigable format. The menu
* appears as an overlay page and can be triggered via keyboard shortcut (Ctrl-Alt-H/Cmd-Alt-H) or programmatically.
*
* @author <a href="mailto:matthewkastor@gmail.com">
* Matthew Christopher Kastor-Inare III </a><br />
* @module
*/
"use strict";
var Editor = require("../editor").Editor;
function showKeyboardShortcuts(editor) {
if (!document.getElementById('kbshortcutmenu')) {
var overlayPage = require('./menu_tools/overlay_page').overlayPage;
var getEditorKeybordShortcuts = require('./menu_tools/get_editor_keyboard_shortcuts').getEditorKeybordShortcuts;
var kb = getEditorKeybordShortcuts(editor);
var el = document.createElement('div');
var commands = kb.reduce(function (previous, current) {
return previous + '<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'
+ current.command + '</span> : '
+ '<span class="ace_optionsMenuKey">' + current.key + '</span></div>';
}, '');
el.id = 'kbshortcutmenu';
el.innerHTML = '<h1>Keyboard Shortcuts</h1>' + commands + '</div>';
overlayPage(editor, el);
}
}
module.exports.init = function (editor) {
Editor.prototype.showKeyboardShortcuts = function () {
showKeyboardShortcuts(this);
};
editor.commands.addCommands([{
name: "showKeyboardShortcuts",
bindKey: {
win: "Ctrl-Alt-h",
mac: "Command-Alt-h"
},
exec:
function (editor, line) {
editor.showKeyboardShortcuts();
}
}]);
};
}); (function() {
ace.require(["ace/ext/keybinding_menu"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
ace.define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"], function(require, exports, module){/**
* ## Interactive Linking Extension
*
* Enables clickable links and hover interactions in the editor when the Control key is pressed. Provides
* keyboard-accelerated navigation by detecting tokens under the cursor and emitting custom events that can be handled
* by external code to implement go-to-definition, symbol navigation, or other link-based functionality.
*
* **Enable:** `editor.setOption("enableLinking", true)`
* @module
*/
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
enableLinking: {
set: function (val) {
if (val) {
this.on("click", onClick);
this.on("mousemove", onMouseMove);
}
else {
this.off("click", onClick);
this.off("mousemove", onMouseMove);
}
},
value: false
}
});
exports.previousLinkingHover = false;
function onMouseMove(e) {
var editor = e.editor;
var ctrl = e.getAccelKey();
if (ctrl) {
var editor = e.editor;
var docPos = e.getDocumentPosition();
var session = editor.session;
var token = session.getTokenAt(docPos.row, docPos.column);
if (exports.previousLinkingHover && exports.previousLinkingHover != token) {
editor._emit("linkHoverOut");
}
editor._emit("linkHover", { position: docPos, token: token });
exports.previousLinkingHover = token;
}
else if (exports.previousLinkingHover) {
editor._emit("linkHoverOut");
exports.previousLinkingHover = false;
}
}
function onClick(e) {
var ctrl = e.getAccelKey();
var button = e.getButton();
if (button == 0 && ctrl) {
var editor = e.editor;
var docPos = e.getDocumentPosition();
var session = editor.session;
var token = session.getTokenAt(docPos.row, docPos.column);
editor._emit("linkClick", { position: docPos, token: token });
}
}
}); (function() {
ace.require(["ace/ext/linking"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,276 @@
ace.define("ace/ext/modelist",["require","exports","module"], function(require, exports, module){/**
* ## File mode detection utility
*
* Provides automatic detection of editor syntax modes based on file paths and extensions. Maps file extensions to
* appropriate Ace Editor syntax highlighting modes for over 100 programming languages and file formats including
* JavaScript, TypeScript, HTML, CSS, Python, Java, C++, and many others. Supports complex extension patterns and
* provides fallback mechanisms for unknown file types.
*
* @module
*/
"use strict";
var modes = [];
function getModeForPath(path) {
var mode = modesByName.text;
var fileName = path.split(/[\/\\]/).pop();
for (var i = 0; i < modes.length; i++) {
if (modes[i].supportsFile(fileName)) {
mode = modes[i];
break;
}
}
return mode;
}
var Mode = /** @class */ (function () {
function Mode(name, caption, extensions) {
this.name = name;
this.caption = caption;
this.mode = "ace/mode/" + name;
this.extensions = extensions;
var re;
if (/\^/.test(extensions)) {
re = extensions.replace(/\|(\^)?/g, function (a, b) {
return "$|" + (b ? "^" : "^.*\\.");
}) + "$";
}
else {
re = "\\.(" + extensions + ")$";
}
this.extRe = new RegExp(re, "gi");
}
Mode.prototype.supportsFile = function (filename) {
return filename.match(this.extRe);
};
return Mode;
}());
var supportedModes = {
ABAP: ["abap"],
ABC: ["abc"],
ActionScript: ["as"],
ADA: ["ada|adb"],
Alda: ["alda"],
Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],
Apex: ["apex|cls|trigger|tgr"],
AQL: ["aql"],
AsciiDoc: ["asciidoc|adoc"],
ASL: ["dsl|asl|asl.json"],
Assembly_ARM32: ["s"],
Assembly_x86: ["asm|a"],
Astro: ["astro"],
AutoHotKey: ["ahk"],
Basic: ["bas|bak"],
BatchFile: ["bat|cmd"],
BibTeX: ["bib"],
C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"],
C9Search: ["c9search_results"],
Cirru: ["cirru|cr"],
Clojure: ["clj|cljs"],
Clue: ["clue"],
Cobol: ["CBL|COB"],
coffee: ["coffee|cf|cson|^Cakefile"],
ColdFusion: ["cfm|cfc"],
Crystal: ["cr"],
CSharp: ["cs"],
Csound_Document: ["csd"],
Csound_Orchestra: ["orc"],
Csound_Score: ["sco"],
CSS: ["css"],
CSV: ["csv"],
Curly: ["curly"],
Cuttlefish: ["conf"],
D: ["d|di"],
Dart: ["dart"],
Diff: ["diff|patch"],
Django: ["djt|html.djt|dj.html|djhtml"],
Dockerfile: ["^Dockerfile"],
Dot: ["dot"],
Drools: ["drl"],
Edifact: ["edi"],
Eiffel: ["e|ge"],
EJS: ["ejs"],
Elixir: ["ex|exs"],
Elm: ["elm"],
Erlang: ["erl|hrl"],
Flix: ["flix"],
Forth: ["frt|fs|ldr|fth|4th"],
Fortran: ["f|f90"],
FSharp: ["fsi|fs|ml|mli|fsx|fsscript"],
FSL: ["fsl"],
FTL: ["ftl"],
Gcode: ["gcode"],
Gherkin: ["feature"],
Gitignore: ["^.gitignore"],
Glsl: ["glsl|frag|vert"],
Gobstones: ["gbs"],
golang: ["go"],
GraphQLSchema: ["gql"],
Groovy: ["groovy"],
HAML: ["haml"],
Handlebars: ["hbs|handlebars|tpl|mustache"],
Haskell: ["hs"],
Haskell_Cabal: ["cabal"],
haXe: ["hx"],
Hjson: ["hjson"],
HTML: ["html|htm|xhtml|we|wpy"],
HTML_Elixir: ["eex|html.eex"],
HTML_Ruby: ["erb|rhtml|html.erb"],
INI: ["ini|conf|cfg|prefs"],
Io: ["io"],
Ion: ["ion"],
Jack: ["jack"],
Jade: ["jade|pug"],
Java: ["java"],
JavaScript: ["js|jsm|cjs|mjs"],
JEXL: ["jexl"],
JSON: ["json"],
JSON5: ["json5"],
JSONiq: ["jq"],
JSP: ["jsp"],
JSSM: ["jssm|jssm_state"],
JSX: ["jsx"],
Julia: ["jl"],
Kotlin: ["kt|kts"],
LaTeX: ["tex|latex|ltx|bib"],
Latte: ["latte"],
LESS: ["less"],
Liquid: ["liquid"],
Lisp: ["lisp"],
LiveScript: ["ls"],
Log: ["log"],
LogiQL: ["logic|lql"],
Logtalk: ["lgt"],
LSL: ["lsl"],
Lua: ["lua"],
LuaPage: ["lp"],
Lucene: ["lucene"],
Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],
Markdown: ["md|markdown"],
Mask: ["mask"],
MATLAB: ["matlab"],
Maze: ["mz"],
MediaWiki: ["wiki|mediawiki"],
MEL: ["mel"],
MIPS: ["s|asm"],
MIXAL: ["mixal"],
MUSHCode: ["mc|mush"],
MySQL: ["mysql"],
Nasal: ["nas"],
Nginx: ["nginx|conf"],
Nim: ["nim"],
Nix: ["nix"],
NSIS: ["nsi|nsh"],
Nunjucks: ["nunjucks|nunjs|nj|njk"],
ObjectiveC: ["m|mm"],
OCaml: ["ml|mli"],
Odin: ["odin"],
PartiQL: ["partiql|pql"],
Pascal: ["pas|p"],
Perl: ["pl|pm"],
pgSQL: ["pgsql"],
PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],
PHP_Laravel_blade: ["blade.php"],
Pig: ["pig"],
PLSQL: ["plsql"],
Powershell: ["ps1"],
Praat: ["praat|praatscript|psc|proc"],
Prisma: ["prisma"],
Prolog: ["plg|prolog"],
Properties: ["properties"],
Protobuf: ["proto"],
PRQL: ["prql"],
Puppet: ["epp|pp"],
Python: ["py"],
QML: ["qml"],
R: ["r"],
Raku: ["raku|rakumod|rakutest|p6|pl6|pm6"],
Razor: ["cshtml|asp"],
RDoc: ["Rd"],
Red: ["red|reds"],
RHTML: ["Rhtml"],
Robot: ["robot|resource"],
RST: ["rst"],
Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],
Rust: ["rs"],
SaC: ["sac"],
SASS: ["sass"],
SCAD: ["scad"],
Scala: ["scala|sbt"],
Scheme: ["scm|sm|rkt|oak|scheme"],
Scrypt: ["scrypt"],
SCSS: ["scss"],
SH: ["sh|bash|^.bashrc"],
SJS: ["sjs"],
Slim: ["slim|skim"],
Smarty: ["smarty|tpl"],
Smithy: ["smithy"],
snippets: ["snippets"],
Soy_Template: ["soy"],
Space: ["space"],
SPARQL: ["rq"],
SQL: ["sql"],
SQLServer: ["sqlserver"],
Stylus: ["styl|stylus"],
SVG: ["svg"],
Swift: ["swift"],
Tcl: ["tcl"],
Terraform: ["tf", "tfvars", "terragrunt"],
Tex: ["tex"],
Text: ["txt"],
Textile: ["textile"],
Toml: ["toml"],
TSV: ["tsv"],
TSX: ["tsx"],
Turtle: ["ttl"],
Twig: ["twig|swig"],
Typescript: ["ts|mts|cts|typescript|str"],
Vala: ["vala"],
VBScript: ["vbs|vb"],
Velocity: ["vm"],
Verilog: ["v|vh|sv|svh"],
VHDL: ["vhd|vhdl"],
Visualforce: ["vfp|component|page"],
Vue: ["vue"],
Wollok: ["wlk|wpgm|wtest"],
XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],
XQuery: ["xq"],
YAML: ["yaml|yml"],
Zeek: ["zeek|bro"],
Zig: ["zig"]
};
var nameOverrides = {
ObjectiveC: "Objective-C",
CSharp: "C#",
golang: "Go",
C_Cpp: "C and C++",
Csound_Document: "Csound Document",
Csound_Orchestra: "Csound",
Csound_Score: "Csound Score",
coffee: "CoffeeScript",
HTML_Ruby: "HTML (Ruby)",
HTML_Elixir: "HTML (Elixir)",
FTL: "FreeMarker",
PHP_Laravel_blade: "PHP (Blade Template)",
Perl6: "Perl 6",
AutoHotKey: "AutoHotkey / AutoIt"
};
var modesByName = {};
for (var name in supportedModes) {
var data = supportedModes[name];
var displayName = (nameOverrides[name] || name).replace(/_/g, " ");
var filename = name.toLowerCase();
var mode = new Mode(filename, displayName, data[0]);
modesByName[filename] = mode;
modes.push(mode);
}
exports.getModeForPath = getModeForPath;
exports.modes = modes;
exports.modesByName = modesByName;
}); (function() {
ace.require(["ace/ext/modelist"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,863 @@
ace.define("ace/ext/menu_tools/settings_menu.css",["require","exports","module"], function(require, exports, module){module.exports = "#ace_settingsmenu, #kbshortcutmenu {\n background-color: #F7F7F7;\n color: black;\n box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);\n padding: 1em 0.5em 2em 1em;\n overflow: auto;\n position: absolute;\n margin: 0;\n bottom: 0;\n right: 0;\n top: 0;\n z-index: 9991;\n cursor: default;\n}\n\n.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {\n box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);\n background-color: rgba(255, 255, 255, 0.6);\n color: black;\n}\n\n.ace_optionsMenuEntry:hover {\n background-color: rgba(100, 100, 100, 0.1);\n transition: all 0.3s\n}\n\n.ace_closeButton {\n background: rgba(245, 146, 146, 0.5);\n border: 1px solid #F48A8A;\n border-radius: 50%;\n padding: 7px;\n position: absolute;\n right: -8px;\n top: -8px;\n z-index: 100000;\n}\n.ace_closeButton{\n background: rgba(245, 146, 146, 0.9);\n}\n.ace_optionsMenuKey {\n color: darkslateblue;\n font-weight: bold;\n}\n.ace_optionsMenuCommand {\n color: darkcyan;\n font-weight: normal;\n}\n.ace_optionsMenuEntry input, .ace_optionsMenuEntry button {\n vertical-align: middle;\n}\n\n.ace_optionsMenuEntry button[ace_selected_button=true] {\n background: #e7e7e7;\n box-shadow: 1px 0px 2px 0px #adadad inset;\n border-color: #adadad;\n}\n.ace_optionsMenuEntry button {\n background: white;\n border: 1px solid lightgray;\n margin: 0px;\n}\n.ace_optionsMenuEntry button:hover{\n background: #f0f0f0;\n}";
});
ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/ext/menu_tools/overlay_page","ace/lib/dom","ace/ext/menu_tools/settings_menu.css"], function(require, exports, module){/**
* ## Overlay Page utility
*
* Provides modal overlay functionality for displaying editor extension interfaces. Creates a full-screen overlay with
* configurable backdrop behavior, keyboard navigation (ESC to close), and focus management. Used by various extensions
* to display menus, settings panels, and other interactive content over the editor interface.
*
* **Usage:**
* ```javascript
* var overlayPage = require('./overlay_page').overlayPage;
* var contentElement = document.createElement('div');
* contentElement.innerHTML = '<h1>Settings</h1>';
*
* var overlay = overlayPage(editor, contentElement, function() {
* console.log('Overlay closed');
* });
* ```
*
* @module
*/
'use strict';
var dom = require("../../lib/dom");
var cssText = require("./settings_menu.css");
dom.importCssString(cssText, "settings_menu.css", false);
module.exports.overlayPage = function overlayPage(editor, contentElement, callback) {
var closer = document.createElement('div');
var ignoreFocusOut = false;
function documentEscListener(e) {
if (e.keyCode === 27) {
close();
}
}
function close() {
if (!closer)
return;
document.removeEventListener('keydown', documentEscListener);
closer.parentNode.removeChild(closer);
if (editor) {
editor.focus();
}
closer = null;
callback && callback();
}
function setIgnoreFocusOut(ignore) {
ignoreFocusOut = ignore;
if (ignore) {
closer.style.pointerEvents = "none";
contentElement.style.pointerEvents = "auto";
}
}
closer.style.cssText = 'margin: 0; padding: 0; ' +
'position: fixed; top:0; bottom:0; left:0; right:0;' +
'z-index: 9990; ' +
(editor ? 'background-color: rgba(0, 0, 0, 0.3);' : '');
closer.addEventListener('click', function (e) {
if (!ignoreFocusOut) {
close();
}
});
document.addEventListener('keydown', documentEscListener);
contentElement.addEventListener('click', function (e) {
e.stopPropagation();
});
closer.appendChild(contentElement);
document.body.appendChild(closer);
if (editor) {
editor.blur();
}
return {
close: close,
setIgnoreFocusOut: setIgnoreFocusOut
};
};
});
ace.define("ace/ext/settings_menu",["require","exports","module","ace/ext/options","ace/ext/menu_tools/overlay_page","ace/editor"], function(require, exports, module){/**
* ## Interactive Settings Menu Extension
*
* Provides settings interface for the Ace editor that displays dynamically generated configuration options based on
* the current editor state. The menu appears as an overlay panel allowing users to modify editor options, themes,
* modes, and other settings through an intuitive graphical interface.
*
* **Usage:**
* ```javascript
* editor.showSettingsMenu();
* ```
*
* The extension automatically registers the `showSettingsMenu` command and method
* on the editor instance when initialized.
*
* @author <a href="mailto:matthewkastor@gmail.com">
* Matthew Christopher Kastor-Inare III </a><br />
*
* @module
*/
"use strict";
var OptionPanel = require("./options").OptionPanel;
var overlayPage = require('./menu_tools/overlay_page').overlayPage;
function showSettingsMenu(editor) {
if (!document.getElementById('ace_settingsmenu')) {
var options = new OptionPanel(editor);
options.render();
options.container.id = "ace_settingsmenu";
overlayPage(editor, options.container);
options.container.querySelector("select,input,button,checkbox").focus();
}
}
module.exports.init = function () {
var Editor = require("../editor").Editor;
Editor.prototype.showSettingsMenu = function () {
showSettingsMenu(this);
};
};
});
ace.define("ace/ext/modelist",["require","exports","module"], function(require, exports, module){/**
* ## File mode detection utility
*
* Provides automatic detection of editor syntax modes based on file paths and extensions. Maps file extensions to
* appropriate Ace Editor syntax highlighting modes for over 100 programming languages and file formats including
* JavaScript, TypeScript, HTML, CSS, Python, Java, C++, and many others. Supports complex extension patterns and
* provides fallback mechanisms for unknown file types.
*
* @module
*/
"use strict";
var modes = [];
function getModeForPath(path) {
var mode = modesByName.text;
var fileName = path.split(/[\/\\]/).pop();
for (var i = 0; i < modes.length; i++) {
if (modes[i].supportsFile(fileName)) {
mode = modes[i];
break;
}
}
return mode;
}
var Mode = /** @class */ (function () {
function Mode(name, caption, extensions) {
this.name = name;
this.caption = caption;
this.mode = "ace/mode/" + name;
this.extensions = extensions;
var re;
if (/\^/.test(extensions)) {
re = extensions.replace(/\|(\^)?/g, function (a, b) {
return "$|" + (b ? "^" : "^.*\\.");
}) + "$";
}
else {
re = "\\.(" + extensions + ")$";
}
this.extRe = new RegExp(re, "gi");
}
Mode.prototype.supportsFile = function (filename) {
return filename.match(this.extRe);
};
return Mode;
}());
var supportedModes = {
ABAP: ["abap"],
ABC: ["abc"],
ActionScript: ["as"],
ADA: ["ada|adb"],
Alda: ["alda"],
Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],
Apex: ["apex|cls|trigger|tgr"],
AQL: ["aql"],
AsciiDoc: ["asciidoc|adoc"],
ASL: ["dsl|asl|asl.json"],
Assembly_ARM32: ["s"],
Assembly_x86: ["asm|a"],
Astro: ["astro"],
AutoHotKey: ["ahk"],
Basic: ["bas|bak"],
BatchFile: ["bat|cmd"],
BibTeX: ["bib"],
C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"],
C9Search: ["c9search_results"],
Cirru: ["cirru|cr"],
Clojure: ["clj|cljs"],
Clue: ["clue"],
Cobol: ["CBL|COB"],
coffee: ["coffee|cf|cson|^Cakefile"],
ColdFusion: ["cfm|cfc"],
Crystal: ["cr"],
CSharp: ["cs"],
Csound_Document: ["csd"],
Csound_Orchestra: ["orc"],
Csound_Score: ["sco"],
CSS: ["css"],
CSV: ["csv"],
Curly: ["curly"],
Cuttlefish: ["conf"],
D: ["d|di"],
Dart: ["dart"],
Diff: ["diff|patch"],
Django: ["djt|html.djt|dj.html|djhtml"],
Dockerfile: ["^Dockerfile"],
Dot: ["dot"],
Drools: ["drl"],
Edifact: ["edi"],
Eiffel: ["e|ge"],
EJS: ["ejs"],
Elixir: ["ex|exs"],
Elm: ["elm"],
Erlang: ["erl|hrl"],
Flix: ["flix"],
Forth: ["frt|fs|ldr|fth|4th"],
Fortran: ["f|f90"],
FSharp: ["fsi|fs|ml|mli|fsx|fsscript"],
FSL: ["fsl"],
FTL: ["ftl"],
Gcode: ["gcode"],
Gherkin: ["feature"],
Gitignore: ["^.gitignore"],
Glsl: ["glsl|frag|vert"],
Gobstones: ["gbs"],
golang: ["go"],
GraphQLSchema: ["gql"],
Groovy: ["groovy"],
HAML: ["haml"],
Handlebars: ["hbs|handlebars|tpl|mustache"],
Haskell: ["hs"],
Haskell_Cabal: ["cabal"],
haXe: ["hx"],
Hjson: ["hjson"],
HTML: ["html|htm|xhtml|we|wpy"],
HTML_Elixir: ["eex|html.eex"],
HTML_Ruby: ["erb|rhtml|html.erb"],
INI: ["ini|conf|cfg|prefs"],
Io: ["io"],
Ion: ["ion"],
Jack: ["jack"],
Jade: ["jade|pug"],
Java: ["java"],
JavaScript: ["js|jsm|cjs|mjs"],
JEXL: ["jexl"],
JSON: ["json"],
JSON5: ["json5"],
JSONiq: ["jq"],
JSP: ["jsp"],
JSSM: ["jssm|jssm_state"],
JSX: ["jsx"],
Julia: ["jl"],
Kotlin: ["kt|kts"],
LaTeX: ["tex|latex|ltx|bib"],
Latte: ["latte"],
LESS: ["less"],
Liquid: ["liquid"],
Lisp: ["lisp"],
LiveScript: ["ls"],
Log: ["log"],
LogiQL: ["logic|lql"],
Logtalk: ["lgt"],
LSL: ["lsl"],
Lua: ["lua"],
LuaPage: ["lp"],
Lucene: ["lucene"],
Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],
Markdown: ["md|markdown"],
Mask: ["mask"],
MATLAB: ["matlab"],
Maze: ["mz"],
MediaWiki: ["wiki|mediawiki"],
MEL: ["mel"],
MIPS: ["s|asm"],
MIXAL: ["mixal"],
MUSHCode: ["mc|mush"],
MySQL: ["mysql"],
Nasal: ["nas"],
Nginx: ["nginx|conf"],
Nim: ["nim"],
Nix: ["nix"],
NSIS: ["nsi|nsh"],
Nunjucks: ["nunjucks|nunjs|nj|njk"],
ObjectiveC: ["m|mm"],
OCaml: ["ml|mli"],
Odin: ["odin"],
PartiQL: ["partiql|pql"],
Pascal: ["pas|p"],
Perl: ["pl|pm"],
pgSQL: ["pgsql"],
PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],
PHP_Laravel_blade: ["blade.php"],
Pig: ["pig"],
PLSQL: ["plsql"],
Powershell: ["ps1"],
Praat: ["praat|praatscript|psc|proc"],
Prisma: ["prisma"],
Prolog: ["plg|prolog"],
Properties: ["properties"],
Protobuf: ["proto"],
PRQL: ["prql"],
Puppet: ["epp|pp"],
Python: ["py"],
QML: ["qml"],
R: ["r"],
Raku: ["raku|rakumod|rakutest|p6|pl6|pm6"],
Razor: ["cshtml|asp"],
RDoc: ["Rd"],
Red: ["red|reds"],
RHTML: ["Rhtml"],
Robot: ["robot|resource"],
RST: ["rst"],
Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],
Rust: ["rs"],
SaC: ["sac"],
SASS: ["sass"],
SCAD: ["scad"],
Scala: ["scala|sbt"],
Scheme: ["scm|sm|rkt|oak|scheme"],
Scrypt: ["scrypt"],
SCSS: ["scss"],
SH: ["sh|bash|^.bashrc"],
SJS: ["sjs"],
Slim: ["slim|skim"],
Smarty: ["smarty|tpl"],
Smithy: ["smithy"],
snippets: ["snippets"],
Soy_Template: ["soy"],
Space: ["space"],
SPARQL: ["rq"],
SQL: ["sql"],
SQLServer: ["sqlserver"],
Stylus: ["styl|stylus"],
SVG: ["svg"],
Swift: ["swift"],
Tcl: ["tcl"],
Terraform: ["tf", "tfvars", "terragrunt"],
Tex: ["tex"],
Text: ["txt"],
Textile: ["textile"],
Toml: ["toml"],
TSV: ["tsv"],
TSX: ["tsx"],
Turtle: ["ttl"],
Twig: ["twig|swig"],
Typescript: ["ts|mts|cts|typescript|str"],
Vala: ["vala"],
VBScript: ["vbs|vb"],
Velocity: ["vm"],
Verilog: ["v|vh|sv|svh"],
VHDL: ["vhd|vhdl"],
Visualforce: ["vfp|component|page"],
Vue: ["vue"],
Wollok: ["wlk|wpgm|wtest"],
XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],
XQuery: ["xq"],
YAML: ["yaml|yml"],
Zeek: ["zeek|bro"],
Zig: ["zig"]
};
var nameOverrides = {
ObjectiveC: "Objective-C",
CSharp: "C#",
golang: "Go",
C_Cpp: "C and C++",
Csound_Document: "Csound Document",
Csound_Orchestra: "Csound",
Csound_Score: "Csound Score",
coffee: "CoffeeScript",
HTML_Ruby: "HTML (Ruby)",
HTML_Elixir: "HTML (Elixir)",
FTL: "FreeMarker",
PHP_Laravel_blade: "PHP (Blade Template)",
Perl6: "Perl 6",
AutoHotKey: "AutoHotkey / AutoIt"
};
var modesByName = {};
for (var name in supportedModes) {
var data = supportedModes[name];
var displayName = (nameOverrides[name] || name).replace(/_/g, " ");
var filename = name.toLowerCase();
var mode = new Mode(filename, displayName, data[0]);
modesByName[filename] = mode;
modes.push(mode);
}
exports.getModeForPath = getModeForPath;
exports.modes = modes;
exports.modesByName = modesByName;
});
ace.define("ace/ext/themelist",["require","exports","module"], function(require, exports, module){/**
* ## Theme enumeration utility
*
* Provides theme management for the Ace Editor by generating and organizing available themes into
* categorized collections. Automatically maps theme data into structured objects containing theme metadata including
* display captions, theme paths, brightness classification (dark/light), and normalized names. Exports both an
* indexed theme collection and a complete themes array for easy integration with theme selection components
* and configuration systems.
*
* @author <a href="mailto:matthewkastor@gmail.com">
* Matthew Christopher Kastor-Inare III </a><br />
* @module
*/
"use strict";
var themeData = [
["Chrome"],
["Clouds"],
["Crimson Editor"],
["Dawn"],
["Dreamweaver"],
["Eclipse"],
["GitHub Light Default"],
["GitHub (Legacy)", "github", "light"],
["IPlastic"],
["Solarized Light"],
["TextMate"],
["Tomorrow"],
["XCode"],
["Kuroir"],
["KatzenMilch"],
["SQL Server", "sqlserver", "light"],
["CloudEditor", "cloud_editor", "light"],
["Ambiance", "ambiance", "dark"],
["Chaos", "chaos", "dark"],
["Clouds Midnight", "clouds_midnight", "dark"],
["Dracula", "", "dark"],
["Cobalt", "cobalt", "dark"],
["Gruvbox", "gruvbox", "dark"],
["Green on Black", "gob", "dark"],
["idle Fingers", "idle_fingers", "dark"],
["krTheme", "kr_theme", "dark"],
["Merbivore", "merbivore", "dark"],
["Merbivore Soft", "merbivore_soft", "dark"],
["Mono Industrial", "mono_industrial", "dark"],
["Monokai", "monokai", "dark"],
["Nord Dark", "nord_dark", "dark"],
["One Dark", "one_dark", "dark"],
["Pastel on dark", "pastel_on_dark", "dark"],
["Solarized Dark", "solarized_dark", "dark"],
["Terminal", "terminal", "dark"],
["Tomorrow Night", "tomorrow_night", "dark"],
["Tomorrow Night Blue", "tomorrow_night_blue", "dark"],
["Tomorrow Night Bright", "tomorrow_night_bright", "dark"],
["Tomorrow Night 80s", "tomorrow_night_eighties", "dark"],
["Twilight", "twilight", "dark"],
["Vibrant Ink", "vibrant_ink", "dark"],
["GitHub Dark", "github_dark", "dark"],
["CloudEditor Dark", "cloud_editor_dark", "dark"]
];
exports.themesByName = {};
exports.themes = themeData.map(function (data) {
var name = data[1] || data[0].replace(/ /g, "_").toLowerCase();
var theme = {
caption: data[0],
theme: "ace/theme/" + name,
isDark: data[2] == "dark",
name: name
};
exports.themesByName[name] = theme;
return theme;
});
});
ace.define("ace/ext/options",["require","exports","module","ace/ext/settings_menu","ace/ext/menu_tools/overlay_page","ace/lib/dom","ace/lib/oop","ace/config","ace/lib/event_emitter","ace/ext/modelist","ace/ext/themelist"], function(require, exports, module){/**
* ## Settings Menu extension
*
* Provides a settings panel for configuring editor options through an interactive UI.
* Creates a tabular interface with grouped configuration options including themes, modes, keybindings,
* font settings, display preferences, and advanced editor behaviors. Supports dynamic option rendering
* with various input types (dropdowns, checkboxes, number inputs, button bars) and real-time updates.
*
* **Usage:**
* ```javascript
* var OptionPanel = require("ace/ext/settings_menu").OptionPanel;
* var panel = new OptionPanel(editor);
* panel.render();
* ```
*
* @module
*/
"use strict";
require("./menu_tools/overlay_page");
var dom = require("../lib/dom");
var oop = require("../lib/oop");
var config = require("../config");
var EventEmitter = require("../lib/event_emitter").EventEmitter;
var buildDom = dom.buildDom;
var modelist = require("./modelist");
var themelist = require("./themelist");
var themes = { Bright: [], Dark: [] };
themelist.themes.forEach(function (x) {
themes[x.isDark ? "Dark" : "Bright"].push({ caption: x.caption, value: x.theme });
});
var modes = modelist.modes.map(function (x) {
return { caption: x.caption, value: x.mode };
});
var optionGroups = {
Main: {
Mode: {
path: "mode",
type: "select",
items: modes
},
Theme: {
path: "theme",
type: "select",
items: themes
},
"Keybinding": {
type: "buttonBar",
path: "keyboardHandler",
items: [
{ caption: "Ace", value: null },
{ caption: "Vim", value: "ace/keyboard/vim" },
{ caption: "Emacs", value: "ace/keyboard/emacs" },
{ caption: "Sublime", value: "ace/keyboard/sublime" },
{ caption: "VSCode", value: "ace/keyboard/vscode" }
]
},
"Font Size": {
path: "fontSize",
type: "number",
defaultValue: 12,
defaults: [
{ caption: "12px", value: 12 },
{ caption: "24px", value: 24 }
]
},
"Soft Wrap": {
type: "buttonBar",
path: "wrap",
items: [
{ caption: "Off", value: "off" },
{ caption: "View", value: "free" },
{ caption: "margin", value: "printMargin" },
{ caption: "40", value: "40" }
]
},
"Cursor Style": {
path: "cursorStyle",
items: [
{ caption: "Ace", value: "ace" },
{ caption: "Slim", value: "slim" },
{ caption: "Smooth", value: "smooth" },
{ caption: "Smooth And Slim", value: "smooth slim" },
{ caption: "Wide", value: "wide" }
]
},
"Folding": {
path: "foldStyle",
items: [
{ caption: "Manual", value: "manual" },
{ caption: "Mark begin", value: "markbegin" },
{ caption: "Mark begin and end", value: "markbeginend" }
]
},
"Soft Tabs": [{
path: "useSoftTabs"
}, {
ariaLabel: "Tab Size",
path: "tabSize",
type: "number",
values: [2, 3, 4, 8, 16]
}],
"Overscroll": {
type: "buttonBar",
path: "scrollPastEnd",
items: [
{ caption: "None", value: 0 },
{ caption: "Half", value: 0.5 },
{ caption: "Full", value: 1 }
]
}
},
More: {
"Atomic soft tabs": {
path: "navigateWithinSoftTabs"
},
"Enable Behaviours": {
path: "behavioursEnabled"
},
"Wrap with quotes": {
path: "wrapBehavioursEnabled"
},
"Enable Auto Indent": {
path: "enableAutoIndent"
},
"Full Line Selection": {
type: "checkbox",
values: "text|line",
path: "selectionStyle"
},
"Highlight Active Line": {
path: "highlightActiveLine"
},
"Show Invisibles": {
path: "showInvisibles"
},
"Show Indent Guides": {
path: "displayIndentGuides"
},
"Highlight Indent Guides": {
path: "highlightIndentGuides"
},
"Persistent HScrollbar": {
path: "hScrollBarAlwaysVisible"
},
"Persistent VScrollbar": {
path: "vScrollBarAlwaysVisible"
},
"Animate scrolling": {
path: "animatedScroll"
},
"Show Gutter": {
path: "showGutter"
},
"Show Line Numbers": {
path: "showLineNumbers"
},
"Relative Line Numbers": {
path: "relativeLineNumbers"
},
"Fixed Gutter Width": {
path: "fixedWidthGutter"
},
"Show Print Margin": [{
path: "showPrintMargin"
}, {
ariaLabel: "Print Margin",
type: "number",
path: "printMarginColumn"
}],
"Indented Soft Wrap": {
path: "indentedSoftWrap"
},
"Highlight selected word": {
path: "highlightSelectedWord"
},
"Fade Fold Widgets": {
path: "fadeFoldWidgets"
},
"Use textarea for IME": {
path: "useTextareaForIME"
},
"Merge Undo Deltas": {
path: "mergeUndoDeltas",
items: [
{ caption: "Always", value: "always" },
{ caption: "Never", value: "false" },
{ caption: "Timed", value: "true" }
]
},
"Elastic Tabstops": {
path: "useElasticTabstops"
},
"Incremental Search": {
path: "useIncrementalSearch"
},
"Read-only": {
path: "readOnly"
},
"Copy without selection": {
path: "copyWithEmptySelection"
},
"Live Autocompletion": {
path: "enableLiveAutocompletion"
},
"Custom scrollbar": {
path: "customScrollbar"
},
"Use SVG gutter icons": {
path: "useSvgGutterIcons"
},
"Annotations for folded lines": {
path: "showFoldedAnnotations"
},
"Keyboard Accessibility Mode": {
path: "enableKeyboardAccessibility"
},
"Gutter tooltip follows mouse": {
path: "tooltipFollowsMouse",
defaultValue: true
}
}
};
var OptionPanel = /** @class */ (function () {
function OptionPanel(editor, element) {
this.editor = editor;
this.container = element || document.createElement("div");
this.groups = [];
this.options = {};
}
OptionPanel.prototype.add = function (config) {
if (config.Main)
oop.mixin(optionGroups.Main, config.Main);
if (config.More)
oop.mixin(optionGroups.More, config.More);
};
OptionPanel.prototype.render = function () {
this.container.innerHTML = "";
buildDom(["table", { role: "presentation", id: "controls" },
this.renderOptionGroup(optionGroups.Main),
["tr", null, ["td", { colspan: 2 },
["table", { role: "presentation", id: "more-controls" },
this.renderOptionGroup(optionGroups.More)
]
]],
["tr", null, ["td", { colspan: 2 }, "version " + config.version]]
], this.container);
};
OptionPanel.prototype.renderOptionGroup = function (group) {
return Object.keys(group).map(function (key, i) {
var item = group[key];
if (!item.position)
item.position = i / 10000;
if (!item.label)
item.label = key;
return item;
}).sort(function (a, b) {
return a.position - b.position;
}).map(function (item) {
return this.renderOption(item.label, item);
}, this);
};
OptionPanel.prototype.renderOptionControl = function (key, option) {
var self = this;
if (Array.isArray(option)) {
return option.map(function (x) {
return self.renderOptionControl(key, x);
});
}
var control;
var value = self.getOption(option);
if (option.values && option.type != "checkbox") {
if (typeof option.values == "string")
option.values = option.values.split("|");
option.items = option.values.map(function (v) {
return { value: v, name: v };
});
}
if (option.type == "buttonBar") {
control = ["div", { role: "group", "aria-labelledby": option.path + "-label" }, option.items.map(function (item) {
return ["button", {
value: item.value,
ace_selected_button: value == item.value,
'aria-pressed': value == item.value,
onclick: function () {
self.setOption(option, item.value);
var nodes = this.parentNode.querySelectorAll("[ace_selected_button]");
for (var i = 0; i < nodes.length; i++) {
nodes[i].removeAttribute("ace_selected_button");
nodes[i].setAttribute("aria-pressed", false);
}
this.setAttribute("ace_selected_button", true);
this.setAttribute("aria-pressed", true);
}
}, item.desc || item.caption || item.name];
})];
}
else if (option.type == "number") {
control = ["input", { type: "number", value: value || option.defaultValue, style: "width:3em", oninput: function () {
self.setOption(option, parseInt(this.value));
} }];
if (option.ariaLabel) {
control[1]["aria-label"] = option.ariaLabel;
}
else {
control[1].id = key;
}
if (option.defaults) {
control = [control, option.defaults.map(function (item) {
return ["button", { onclick: function () {
var input = this.parentNode.firstChild;
input.value = item.value;
input.oninput();
} }, item.caption];
})];
}
}
else if (option.items) {
var buildItems = function (items) {
return items.map(function (item) {
return ["option", { value: item.value || item.name }, item.desc || item.caption || item.name];
});
};
var items = Array.isArray(option.items)
? buildItems(option.items)
: Object.keys(option.items).map(function (key) {
return ["optgroup", { "label": key }, buildItems(option.items[key])];
});
control = ["select", { id: key, value: value, onchange: function () {
self.setOption(option, this.value);
} }, items];
}
else {
if (typeof option.values == "string")
option.values = option.values.split("|");
if (option.values)
value = value == option.values[1];
control = ["input", { type: "checkbox", id: key, checked: value || null, onchange: function () {
var value = this.checked;
if (option.values)
value = option.values[value ? 1 : 0];
self.setOption(option, value);
} }];
if (option.type == "checkedNumber") {
control = [control, []];
}
}
return control;
};
OptionPanel.prototype.renderOption = function (key, option) {
if (option.path && !option.onchange && !this.editor.$options[option.path])
return;
var path = Array.isArray(option) ? option[0].path : option.path;
this.options[path] = option;
var safeKey = "-" + path;
var safeId = path + "-label";
var control = this.renderOptionControl(safeKey, option);
return ["tr", { class: "ace_optionsMenuEntry" }, ["td",
["label", { for: safeKey, id: safeId }, key]
], ["td", control]];
};
OptionPanel.prototype.setOption = function (option, value) {
if (typeof option == "string")
option = this.options[option];
if (value == "false")
value = false;
if (value == "true")
value = true;
if (value == "null")
value = null;
if (value == "undefined")
value = undefined;
if (typeof value == "string" && parseFloat(value).toString() == value)
value = parseFloat(value);
if (option.onchange)
option.onchange(value);
else if (option.path)
this.editor.setOption(option.path, value);
this._signal("setOption", { name: option.path, value: value });
};
OptionPanel.prototype.getOption = function (option) {
if (option.getValue)
return option.getValue();
return this.editor.getOption(option.path);
};
return OptionPanel;
}());
oop.implement(OptionPanel.prototype, EventEmitter);
exports.OptionPanel = OptionPanel;
exports.optionGroups = optionGroups;
}); (function() {
ace.require(["ace/ext/options"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
ace.define("ace/ext/rtl",["require","exports","module","ace/editor","ace/config"], function(require, exports, module){/**
* ## Right-to-Left (RTL) text support extension
*
* Provides bidirectional text support enabling proper rendering and editing of RTL languages such as Arabic, Hebrew,
* and Persian. Handles text direction detection, cursor positioning, and ensures correct visual behavior for mixed
* LTR/RTL content. Includes keyboard shortcuts for manual text direction control and automatic
* RLE (Right-to-Left Embedding) marker management.
*
* **Configuration Options:**
* - `rtlText`: Enable automatic RTL text detection and handling
* - `rtl`: Force RTL direction for the entire editor
*
* **Keyboard Shortcuts:**
* - `Ctrl-Alt-Shift-L` (Win) / `Cmd-Alt-Shift-L` (Mac): Force left-to-right direction
* - `Ctrl-Alt-Shift-R` (Win) / `Cmd-Alt-Shift-R` (Mac): Force right-to-left direction
*
* **Usage:**
* ```javascript
* editor.setOptions({
* rtlText: true, // Enable automatic RTL detection
* rtl: false // Or force RTL direction
* });
* ```
*
* @module
*/
"use strict";
var commands = [{
name: "leftToRight",
bindKey: { win: "Ctrl-Alt-Shift-L", mac: "Command-Alt-Shift-L" },
exec: function (editor) {
editor.session.$bidiHandler.setRtlDirection(editor, false);
},
readOnly: true
}, {
name: "rightToLeft",
bindKey: { win: "Ctrl-Alt-Shift-R", mac: "Command-Alt-Shift-R" },
exec: function (editor) {
editor.session.$bidiHandler.setRtlDirection(editor, true);
},
readOnly: true
}];
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
rtlText: {
set: function (val) {
if (val) {
this.on("change", onChange);
this.on("changeSelection", onChangeSelection);
this.renderer.on("afterRender", updateLineDirection);
this.commands.on("exec", onCommandEmitted);
this.commands.addCommands(commands);
}
else {
this.off("change", onChange);
this.off("changeSelection", onChangeSelection);
this.renderer.off("afterRender", updateLineDirection);
this.commands.off("exec", onCommandEmitted);
this.commands.removeCommands(commands);
clearTextLayer(this.renderer);
}
this.renderer.updateFull();
}
},
rtl: {
set: function (val) {
this.session.$bidiHandler.$isRtl = val;
if (val) {
this.setOption("rtlText", false);
this.renderer.on("afterRender", updateLineDirection);
this.session.$bidiHandler.seenBidi = true;
}
else {
this.renderer.off("afterRender", updateLineDirection);
clearTextLayer(this.renderer);
}
this.renderer.updateFull();
}
}
});
function onChangeSelection(e, editor) {
var lead = editor.getSelection().lead;
if (editor.session.$bidiHandler.isRtlLine(lead.row)) {
if (lead.column === 0) {
if (editor.session.$bidiHandler.isMoveLeftOperation && lead.row > 0) {
editor.getSelection().moveCursorTo(lead.row - 1, editor.session.getLine(lead.row - 1).length);
}
else {
if (editor.getSelection().isEmpty())
lead.column += 1;
else
lead.setPosition(lead.row, lead.column + 1);
}
}
}
}
function onCommandEmitted(commadEvent) {
commadEvent.editor.session.$bidiHandler.isMoveLeftOperation = /gotoleft|selectleft|backspace|removewordleft/.test(commadEvent.command.name);
}
function onChange(delta, editor) {
var session = editor.session;
session.$bidiHandler.currentRow = null;
if (session.$bidiHandler.isRtlLine(delta.start.row) && delta.action === 'insert' && delta.lines.length > 1) {
for (var row = delta.start.row; row < delta.end.row; row++) {
if (session.getLine(row + 1).charAt(0) !== session.$bidiHandler.RLE)
session.doc.$lines[row + 1] = session.$bidiHandler.RLE + session.getLine(row + 1);
}
}
}
function updateLineDirection(e, renderer) {
var session = renderer.session;
var $bidiHandler = session.$bidiHandler;
var cells = renderer.$textLayer.$lines.cells;
var width = renderer.layerConfig.width - renderer.layerConfig.padding + "px";
cells.forEach(function (cell) {
var style = cell.element.style;
if ($bidiHandler && $bidiHandler.isRtlLine(cell.row)) {
style.direction = "rtl";
style.textAlign = "right";
style.width = width;
}
else {
style.direction = "";
style.textAlign = "";
style.width = "";
}
});
}
function clearTextLayer(renderer) {
var lines = renderer.$textLayer.$lines;
lines.cells.forEach(clear);
lines.cellCache.forEach(clear);
function clear(cell) {
var style = cell.element.style;
style.direction = style.textAlign = style.width = "";
}
}
}); (function() {
ace.require(["ace/ext/rtl"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,385 @@
ace.define("ace/ext/searchbox-css",["require","exports","module"], function(require, exports, module){module.exports = "\n\n/* ------------------------------------------------------------------------------------------\n * Editor Search Form\n * --------------------------------------------------------------------------------------- */\n.ace_search {\n background-color: #ddd;\n color: #666;\n border: 1px solid #cbcbcb;\n border-top: 0 none;\n overflow: hidden;\n margin: 0;\n padding: 4px 6px 0 4px;\n position: absolute;\n top: 0;\n z-index: 99;\n white-space: normal;\n}\n.ace_search.left {\n border-left: 0 none;\n border-radius: 0px 0px 5px 0px;\n left: 0;\n}\n.ace_search.right {\n border-radius: 0px 0px 0px 5px;\n border-right: 0 none;\n right: 0;\n}\n\n.ace_search_form, .ace_replace_form {\n margin: 0 20px 4px 0;\n overflow: hidden;\n line-height: 1.9;\n}\n.ace_replace_form {\n margin-right: 0;\n}\n.ace_search_form.ace_nomatch {\n outline: 1px solid red;\n}\n\n.ace_search_field {\n border-radius: 3px 0 0 3px;\n background-color: white;\n color: black;\n border: 1px solid #cbcbcb;\n border-right: 0 none;\n outline: 0;\n padding: 0;\n font-size: inherit;\n margin: 0;\n line-height: inherit;\n padding: 0 6px;\n min-width: 17em;\n vertical-align: top;\n min-height: 1.8em;\n box-sizing: content-box;\n}\n.ace_searchbtn {\n border: 1px solid #cbcbcb;\n line-height: inherit;\n display: inline-block;\n padding: 0 6px;\n background: #fff;\n border-right: 0 none;\n border-left: 1px solid #dcdcdc;\n cursor: pointer;\n margin: 0;\n position: relative;\n color: #666;\n}\n.ace_searchbtn:last-child {\n border-radius: 0 3px 3px 0;\n border-right: 1px solid #cbcbcb;\n}\n.ace_searchbtn:disabled {\n background: none;\n cursor: default;\n}\n.ace_searchbtn:hover {\n background-color: #eef1f6;\n}\n.ace_searchbtn.prev, .ace_searchbtn.next {\n padding: 0px 0.7em\n}\n.ace_searchbtn.prev:after, .ace_searchbtn.next:after {\n content: \"\";\n border: solid 2px #888;\n width: 0.5em;\n height: 0.5em;\n border-width: 2px 0 0 2px;\n display:inline-block;\n transform: rotate(-45deg);\n}\n.ace_searchbtn.next:after {\n border-width: 0 2px 2px 0 ;\n}\n.ace_searchbtn_close {\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;\n border-radius: 50%;\n border: 0 none;\n color: #656565;\n cursor: pointer;\n font: 16px/16px Arial;\n padding: 0;\n height: 14px;\n width: 14px;\n top: 9px;\n right: 7px;\n position: absolute;\n}\n.ace_searchbtn_close:hover {\n background-color: #656565;\n background-position: 50% 100%;\n color: white;\n}\n\n.ace_button {\n margin-left: 2px;\n cursor: pointer;\n -webkit-user-select: none;\n -moz-user-select: none;\n -o-user-select: none;\n -ms-user-select: none;\n user-select: none;\n overflow: hidden;\n opacity: 0.7;\n border: 1px solid rgba(100,100,100,0.23);\n padding: 1px;\n box-sizing: border-box!important;\n color: black;\n}\n\n.ace_button:hover {\n background-color: #eee;\n opacity:1;\n}\n.ace_button:active {\n background-color: #ddd;\n}\n\n.ace_button.checked {\n border-color: #3399ff;\n opacity:1;\n}\n\n.ace_search_options{\n margin-bottom: 3px;\n text-align: right;\n -webkit-user-select: none;\n -moz-user-select: none;\n -o-user-select: none;\n -ms-user-select: none;\n user-select: none;\n clear: both;\n}\n\n.ace_search_counter {\n float: left;\n font-family: arial;\n padding: 0 8px;\n}";
});
ace.define("ace/ext/searchbox",["require","exports","module","ace/ext/searchbox","ace/ext/searchbox","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/ext/searchbox-css","ace/keyboard/hash_handler","ace/lib/keys","ace/config"], function(require, exports, module){/**
* ## Interactive search and replace UI extension for text editing
*
* Provides a floating search box interface with find/replace functionality including live search results, regex
* support, case sensitivity options, whole word matching, and scoped selection searching. Features keyboard shortcuts
* for quick access and navigation, with visual feedback for search matches and a counter showing current position
* in results.
*
* **Key Features:**
* - Real-time search with highlighted matches
* - Find and replace with individual or bulk operations
* - Advanced options: regex, case sensitivity, whole words, search in selection
* - Keyboard navigation and shortcuts
* - Visual match counter and no-match indicators
*
* **Usage:**
* ```javascript
* // Show search box
* require("ace/ext/searchbox").Search(editor);
*
* // Show with replace functionality
* require("ace/ext/searchbox").Search(editor, true);
* ```
*
* @module
*/
"use strict";
var dom = require("../lib/dom");
var lang = require("../lib/lang");
var event = require("../lib/event");
var searchboxCss = require("./searchbox-css");
var HashHandler = require("../keyboard/hash_handler").HashHandler;
var keyUtil = require("../lib/keys");
var nls = require("../config").nls;
var MAX_COUNT = 999;
dom.importCssString(searchboxCss, "ace_searchbox", false);
var SearchBox = /** @class */ (function () {
function SearchBox(editor, range, showReplaceForm) {
this.activeInput;
this.element = dom.buildDom(["div", { class: "ace_search right" },
["span", { action: "hide", class: "ace_searchbtn_close" }],
["div", { class: "ace_search_form" },
["input", { class: "ace_search_field", placeholder: nls("search-box.find.placeholder", "Search for"), spellcheck: "false" }],
["span", { action: "findPrev", class: "ace_searchbtn prev" }, "\u200b"],
["span", { action: "findNext", class: "ace_searchbtn next" }, "\u200b"],
["span", { action: "findAll", class: "ace_searchbtn", title: "Alt-Enter" }, nls("search-box.find-all.text", "All")]
],
["div", { class: "ace_replace_form" },
["input", { class: "ace_search_field", placeholder: nls("search-box.replace.placeholder", "Replace with"), spellcheck: "false" }],
["span", { action: "replaceAndFindNext", class: "ace_searchbtn" }, nls("search-box.replace-next.text", "Replace")],
["span", { action: "replaceAll", class: "ace_searchbtn" }, nls("search-box.replace-all.text", "All")]
],
["div", { class: "ace_search_options" },
["span", { action: "toggleReplace", class: "ace_button", title: nls("search-box.toggle-replace.title", "Toggle Replace mode"),
style: "float:left;margin-top:-2px;padding:0 5px;" }, "+"],
["span", { class: "ace_search_counter" }],
["span", { action: "toggleRegexpMode", class: "ace_button", title: nls("search-box.toggle-regexp.title", "RegExp Search") }, ".*"],
["span", { action: "toggleCaseSensitive", class: "ace_button", title: nls("search-box.toggle-case.title", "CaseSensitive Search") }, "Aa"],
["span", { action: "toggleWholeWords", class: "ace_button", title: nls("search-box.toggle-whole-word.title", "Whole Word Search") }, "\\b"],
["span", { action: "searchInSelection", class: "ace_button", title: nls("search-box.toggle-in-selection.title", "Search In Selection") }, "S"]
]
]);
this.setSession = this.setSession.bind(this);
this.$onEditorInput = this.onEditorInput.bind(this);
this.$init();
this.setEditor(editor);
dom.importCssString(searchboxCss, "ace_searchbox", editor.container);
event.addListener(this.element, "touchstart", function (e) { e.stopPropagation(); }, editor);
}
SearchBox.prototype.setEditor = function (editor) {
editor.searchBox = this;
editor.renderer.scroller.appendChild(this.element);
this.editor = editor;
};
SearchBox.prototype.setSession = function (e) {
this.searchRange = null;
this.$syncOptions(true);
};
SearchBox.prototype.onEditorInput = function () {
this.find(false, false, true);
};
SearchBox.prototype.$initElements = function (sb) {
this.searchBox = sb.querySelector(".ace_search_form");
this.replaceBox = sb.querySelector(".ace_replace_form");
this.searchOption = sb.querySelector("[action=searchInSelection]");
this.replaceOption = sb.querySelector("[action=toggleReplace]");
this.regExpOption = sb.querySelector("[action=toggleRegexpMode]");
this.caseSensitiveOption = sb.querySelector("[action=toggleCaseSensitive]");
this.wholeWordOption = sb.querySelector("[action=toggleWholeWords]");
this.searchInput = this.searchBox.querySelector(".ace_search_field");
this.replaceInput = this.replaceBox.querySelector(".ace_search_field");
this.searchCounter = sb.querySelector(".ace_search_counter");
};
SearchBox.prototype.$init = function () {
var sb = this.element;
this.$initElements(sb);
var _this = this;
event.addListener(sb, "mousedown", function (e) {
setTimeout(function () {
_this.activeInput.focus();
}, 0);
event.stopPropagation(e);
});
event.addListener(sb, "click", function (e) {
var t = e.target || e.srcElement;
var action = t.getAttribute("action");
if (action && _this[action])
_this[action]();
else if (_this.$searchBarKb.commands[action])
_this.$searchBarKb.commands[action].exec(_this);
event.stopPropagation(e);
});
event.addCommandKeyListener(sb, function (e, hashId, keyCode) {
var keyString = keyUtil.keyCodeToString(keyCode);
var command = _this.$searchBarKb.findKeyCommand(hashId, keyString);
if (command && command.exec) {
command.exec(_this);
event.stopEvent(e);
}
});
this.$onChange = lang.delayedCall(function () {
_this.find(false, false);
});
event.addListener(this.searchInput, "input", function () {
_this.$onChange.schedule(20);
});
event.addListener(this.searchInput, "focus", function () {
_this.activeInput = _this.searchInput;
_this.searchInput.value && _this.highlight();
});
event.addListener(this.replaceInput, "focus", function () {
_this.activeInput = _this.replaceInput;
_this.searchInput.value && _this.highlight();
});
};
SearchBox.prototype.setSearchRange = function (range) {
this.searchRange = range;
if (range) {
this.searchRangeMarker = this.editor.session.addMarker(range, "ace_active-line");
}
else if (this.searchRangeMarker) {
this.editor.session.removeMarker(this.searchRangeMarker);
this.searchRangeMarker = null;
}
};
SearchBox.prototype.$syncOptions = function (preventScroll) {
dom.setCssClass(this.replaceOption, "checked", this.searchRange);
dom.setCssClass(this.searchOption, "checked", this.searchOption.checked);
this.replaceOption.textContent = this.replaceOption.checked ? "-" : "+";
dom.setCssClass(this.regExpOption, "checked", this.regExpOption.checked);
dom.setCssClass(this.wholeWordOption, "checked", this.wholeWordOption.checked);
dom.setCssClass(this.caseSensitiveOption, "checked", this.caseSensitiveOption.checked);
var readOnly = this.editor.getReadOnly();
this.replaceOption.style.display = readOnly ? "none" : "";
this.replaceBox.style.display = this.replaceOption.checked && !readOnly ? "" : "none";
this.find(false, false, preventScroll);
};
SearchBox.prototype.highlight = function (re) {
this.editor.session.highlight(re || this.editor.$search.$options.re);
this.editor.renderer.updateBackMarkers();
};
SearchBox.prototype.find = function (skipCurrent, backwards, preventScroll) {
if (!this.editor.session)
return;
var range = this.editor.find(this.searchInput.value, {
skipCurrent: skipCurrent,
backwards: backwards,
wrap: true,
regExp: this.regExpOption.checked,
caseSensitive: this.caseSensitiveOption.checked,
wholeWord: this.wholeWordOption.checked,
preventScroll: preventScroll,
range: this.searchRange
});
var noMatch = !range && this.searchInput.value;
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
this.editor._emit("findSearchBox", { match: !noMatch });
this.highlight();
this.updateCounter();
};
SearchBox.prototype.updateCounter = function () {
var editor = this.editor;
var regex = editor.$search.$options.re;
var supportsUnicodeFlag = regex.unicode;
var all = 0;
var before = 0;
if (regex) {
var value = this.searchRange
? editor.session.getTextRange(this.searchRange)
: editor.getValue();
if (editor.$search.$isMultilineSearch(editor.getLastSearchOptions())) {
value = value.replace(/\r\n|\r|\n/g, "\n");
editor.session.doc.$autoNewLine = "\n";
}
var offset = editor.session.doc.positionToIndex(editor.selection.anchor);
if (this.searchRange)
offset -= editor.session.doc.positionToIndex(this.searchRange.start);
var last = regex.lastIndex = 0;
var m;
while ((m = regex.exec(value))) {
all++;
last = m.index;
if (last <= offset)
before++;
if (all > MAX_COUNT)
break;
if (!m[0]) {
regex.lastIndex = last += lang.skipEmptyMatch(value, last, supportsUnicodeFlag);
if (last >= value.length)
break;
}
}
}
this.searchCounter.textContent = nls("search-box.search-counter", "$0 of $1", [before, (all > MAX_COUNT ? MAX_COUNT + "+" : all)]);
};
SearchBox.prototype.findNext = function () {
this.find(true, false);
};
SearchBox.prototype.findPrev = function () {
this.find(true, true);
};
SearchBox.prototype.findAll = function () {
var range = this.editor.findAll(this.searchInput.value, {
regExp: this.regExpOption.checked,
caseSensitive: this.caseSensitiveOption.checked,
wholeWord: this.wholeWordOption.checked
});
var noMatch = !range && this.searchInput.value;
dom.setCssClass(this.searchBox, "ace_nomatch", noMatch);
this.editor._emit("findSearchBox", { match: !noMatch });
this.highlight();
this.hide();
};
SearchBox.prototype.replace = function () {
if (!this.editor.getReadOnly())
this.editor.replace(this.replaceInput.value);
};
SearchBox.prototype.replaceAndFindNext = function () {
if (!this.editor.getReadOnly()) {
this.editor.replace(this.replaceInput.value);
this.findNext();
}
};
SearchBox.prototype.replaceAll = function () {
if (!this.editor.getReadOnly())
this.editor.replaceAll(this.replaceInput.value);
};
SearchBox.prototype.hide = function () {
this.active = false;
this.setSearchRange(null);
this.editor.off("changeSession", this.setSession);
this.editor.off("input", this.$onEditorInput);
this.element.style.display = "none";
this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb);
this.editor.focus();
};
SearchBox.prototype.show = function (value, isReplace) {
this.active = true;
this.editor.on("changeSession", this.setSession);
this.editor.on("input", this.$onEditorInput);
this.element.style.display = "";
this.replaceOption.checked = isReplace;
if (this.editor.$search.$options.regExp)
value = lang.escapeRegExp(value);
if (value != undefined)
this.searchInput.value = value;
this.searchInput.focus();
this.searchInput.select();
this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb);
this.$syncOptions(true);
};
SearchBox.prototype.isFocused = function () {
var el = document.activeElement;
return el == this.searchInput || el == this.replaceInput;
};
return SearchBox;
}());
var $searchBarKb = new HashHandler();
$searchBarKb.bindKeys({
"Ctrl-f|Command-f": function (sb) {
var isReplace = sb.isReplace = !sb.isReplace;
sb.replaceBox.style.display = isReplace ? "" : "none";
sb.replaceOption.checked = false;
sb.$syncOptions();
sb.searchInput.focus();
},
"Ctrl-H|Command-Option-F": function (sb) {
if (sb.editor.getReadOnly())
return;
sb.replaceOption.checked = true;
sb.$syncOptions();
sb.replaceInput.focus();
},
"Ctrl-G|Command-G": function (sb) {
sb.findNext();
},
"Ctrl-Shift-G|Command-Shift-G": function (sb) {
sb.findPrev();
},
"esc": function (sb) {
setTimeout(function () { sb.hide(); });
},
"Return": function (sb) {
if (sb.activeInput == sb.replaceInput)
sb.replace();
sb.findNext();
},
"Shift-Return": function (sb) {
if (sb.activeInput == sb.replaceInput)
sb.replace();
sb.findPrev();
},
"Alt-Return": function (sb) {
if (sb.activeInput == sb.replaceInput)
sb.replaceAll();
sb.findAll();
},
"Tab": function (sb) {
(sb.activeInput == sb.replaceInput ? sb.searchInput : sb.replaceInput).focus();
}
});
$searchBarKb.addCommands([{
name: "toggleRegexpMode",
bindKey: { win: "Alt-R|Alt-/", mac: "Ctrl-Alt-R|Ctrl-Alt-/" },
exec: function (sb) {
sb.regExpOption.checked = !sb.regExpOption.checked;
sb.$syncOptions();
}
}, {
name: "toggleCaseSensitive",
bindKey: { win: "Alt-C|Alt-I", mac: "Ctrl-Alt-R|Ctrl-Alt-I" },
exec: function (sb) {
sb.caseSensitiveOption.checked = !sb.caseSensitiveOption.checked;
sb.$syncOptions();
}
}, {
name: "toggleWholeWords",
bindKey: { win: "Alt-B|Alt-W", mac: "Ctrl-Alt-B|Ctrl-Alt-W" },
exec: function (sb) {
sb.wholeWordOption.checked = !sb.wholeWordOption.checked;
sb.$syncOptions();
}
}, {
name: "toggleReplace",
exec: function (sb) {
sb.replaceOption.checked = !sb.replaceOption.checked;
sb.$syncOptions();
}
}, {
name: "searchInSelection",
exec: function (sb) {
sb.searchOption.checked = !sb.searchRange;
sb.setSearchRange(sb.searchOption.checked && sb.editor.getSelectionRange());
sb.$syncOptions();
}
}]);
var $closeSearchBarKb = new HashHandler([{
bindKey: "Esc",
name: "closeSearchBar",
exec: function (editor) {
editor.searchBox.hide();
}
}]);
SearchBox.prototype.$searchBarKb = $searchBarKb;
SearchBox.prototype.$closeSearchBarKb = $closeSearchBarKb;
exports.SearchBox = SearchBox;
exports.Search = function (editor, isReplace) {
var sb = editor.searchBox || new SearchBox(editor);
var range = editor.session.selection.getRange();
var value = range.isMultiLine() ? "" : editor.session.getTextRange(range);
sb.show(value, isReplace);
};
}); (function() {
ace.require(["ace/ext/searchbox"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,863 @@
ace.define("ace/ext/menu_tools/settings_menu.css",["require","exports","module"], function(require, exports, module){module.exports = "#ace_settingsmenu, #kbshortcutmenu {\n background-color: #F7F7F7;\n color: black;\n box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);\n padding: 1em 0.5em 2em 1em;\n overflow: auto;\n position: absolute;\n margin: 0;\n bottom: 0;\n right: 0;\n top: 0;\n z-index: 9991;\n cursor: default;\n}\n\n.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {\n box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);\n background-color: rgba(255, 255, 255, 0.6);\n color: black;\n}\n\n.ace_optionsMenuEntry:hover {\n background-color: rgba(100, 100, 100, 0.1);\n transition: all 0.3s\n}\n\n.ace_closeButton {\n background: rgba(245, 146, 146, 0.5);\n border: 1px solid #F48A8A;\n border-radius: 50%;\n padding: 7px;\n position: absolute;\n right: -8px;\n top: -8px;\n z-index: 100000;\n}\n.ace_closeButton{\n background: rgba(245, 146, 146, 0.9);\n}\n.ace_optionsMenuKey {\n color: darkslateblue;\n font-weight: bold;\n}\n.ace_optionsMenuCommand {\n color: darkcyan;\n font-weight: normal;\n}\n.ace_optionsMenuEntry input, .ace_optionsMenuEntry button {\n vertical-align: middle;\n}\n\n.ace_optionsMenuEntry button[ace_selected_button=true] {\n background: #e7e7e7;\n box-shadow: 1px 0px 2px 0px #adadad inset;\n border-color: #adadad;\n}\n.ace_optionsMenuEntry button {\n background: white;\n border: 1px solid lightgray;\n margin: 0px;\n}\n.ace_optionsMenuEntry button:hover{\n background: #f0f0f0;\n}";
});
ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/ext/menu_tools/overlay_page","ace/lib/dom","ace/ext/menu_tools/settings_menu.css"], function(require, exports, module){/**
* ## Overlay Page utility
*
* Provides modal overlay functionality for displaying editor extension interfaces. Creates a full-screen overlay with
* configurable backdrop behavior, keyboard navigation (ESC to close), and focus management. Used by various extensions
* to display menus, settings panels, and other interactive content over the editor interface.
*
* **Usage:**
* ```javascript
* var overlayPage = require('./overlay_page').overlayPage;
* var contentElement = document.createElement('div');
* contentElement.innerHTML = '<h1>Settings</h1>';
*
* var overlay = overlayPage(editor, contentElement, function() {
* console.log('Overlay closed');
* });
* ```
*
* @module
*/
'use strict';
var dom = require("../../lib/dom");
var cssText = require("./settings_menu.css");
dom.importCssString(cssText, "settings_menu.css", false);
module.exports.overlayPage = function overlayPage(editor, contentElement, callback) {
var closer = document.createElement('div');
var ignoreFocusOut = false;
function documentEscListener(e) {
if (e.keyCode === 27) {
close();
}
}
function close() {
if (!closer)
return;
document.removeEventListener('keydown', documentEscListener);
closer.parentNode.removeChild(closer);
if (editor) {
editor.focus();
}
closer = null;
callback && callback();
}
function setIgnoreFocusOut(ignore) {
ignoreFocusOut = ignore;
if (ignore) {
closer.style.pointerEvents = "none";
contentElement.style.pointerEvents = "auto";
}
}
closer.style.cssText = 'margin: 0; padding: 0; ' +
'position: fixed; top:0; bottom:0; left:0; right:0;' +
'z-index: 9990; ' +
(editor ? 'background-color: rgba(0, 0, 0, 0.3);' : '');
closer.addEventListener('click', function (e) {
if (!ignoreFocusOut) {
close();
}
});
document.addEventListener('keydown', documentEscListener);
contentElement.addEventListener('click', function (e) {
e.stopPropagation();
});
closer.appendChild(contentElement);
document.body.appendChild(closer);
if (editor) {
editor.blur();
}
return {
close: close,
setIgnoreFocusOut: setIgnoreFocusOut
};
};
});
ace.define("ace/ext/modelist",["require","exports","module"], function(require, exports, module){/**
* ## File mode detection utility
*
* Provides automatic detection of editor syntax modes based on file paths and extensions. Maps file extensions to
* appropriate Ace Editor syntax highlighting modes for over 100 programming languages and file formats including
* JavaScript, TypeScript, HTML, CSS, Python, Java, C++, and many others. Supports complex extension patterns and
* provides fallback mechanisms for unknown file types.
*
* @module
*/
"use strict";
var modes = [];
function getModeForPath(path) {
var mode = modesByName.text;
var fileName = path.split(/[\/\\]/).pop();
for (var i = 0; i < modes.length; i++) {
if (modes[i].supportsFile(fileName)) {
mode = modes[i];
break;
}
}
return mode;
}
var Mode = /** @class */ (function () {
function Mode(name, caption, extensions) {
this.name = name;
this.caption = caption;
this.mode = "ace/mode/" + name;
this.extensions = extensions;
var re;
if (/\^/.test(extensions)) {
re = extensions.replace(/\|(\^)?/g, function (a, b) {
return "$|" + (b ? "^" : "^.*\\.");
}) + "$";
}
else {
re = "\\.(" + extensions + ")$";
}
this.extRe = new RegExp(re, "gi");
}
Mode.prototype.supportsFile = function (filename) {
return filename.match(this.extRe);
};
return Mode;
}());
var supportedModes = {
ABAP: ["abap"],
ABC: ["abc"],
ActionScript: ["as"],
ADA: ["ada|adb"],
Alda: ["alda"],
Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],
Apex: ["apex|cls|trigger|tgr"],
AQL: ["aql"],
AsciiDoc: ["asciidoc|adoc"],
ASL: ["dsl|asl|asl.json"],
Assembly_ARM32: ["s"],
Assembly_x86: ["asm|a"],
Astro: ["astro"],
AutoHotKey: ["ahk"],
Basic: ["bas|bak"],
BatchFile: ["bat|cmd"],
BibTeX: ["bib"],
C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"],
C9Search: ["c9search_results"],
Cirru: ["cirru|cr"],
Clojure: ["clj|cljs"],
Clue: ["clue"],
Cobol: ["CBL|COB"],
coffee: ["coffee|cf|cson|^Cakefile"],
ColdFusion: ["cfm|cfc"],
Crystal: ["cr"],
CSharp: ["cs"],
Csound_Document: ["csd"],
Csound_Orchestra: ["orc"],
Csound_Score: ["sco"],
CSS: ["css"],
CSV: ["csv"],
Curly: ["curly"],
Cuttlefish: ["conf"],
D: ["d|di"],
Dart: ["dart"],
Diff: ["diff|patch"],
Django: ["djt|html.djt|dj.html|djhtml"],
Dockerfile: ["^Dockerfile"],
Dot: ["dot"],
Drools: ["drl"],
Edifact: ["edi"],
Eiffel: ["e|ge"],
EJS: ["ejs"],
Elixir: ["ex|exs"],
Elm: ["elm"],
Erlang: ["erl|hrl"],
Flix: ["flix"],
Forth: ["frt|fs|ldr|fth|4th"],
Fortran: ["f|f90"],
FSharp: ["fsi|fs|ml|mli|fsx|fsscript"],
FSL: ["fsl"],
FTL: ["ftl"],
Gcode: ["gcode"],
Gherkin: ["feature"],
Gitignore: ["^.gitignore"],
Glsl: ["glsl|frag|vert"],
Gobstones: ["gbs"],
golang: ["go"],
GraphQLSchema: ["gql"],
Groovy: ["groovy"],
HAML: ["haml"],
Handlebars: ["hbs|handlebars|tpl|mustache"],
Haskell: ["hs"],
Haskell_Cabal: ["cabal"],
haXe: ["hx"],
Hjson: ["hjson"],
HTML: ["html|htm|xhtml|we|wpy"],
HTML_Elixir: ["eex|html.eex"],
HTML_Ruby: ["erb|rhtml|html.erb"],
INI: ["ini|conf|cfg|prefs"],
Io: ["io"],
Ion: ["ion"],
Jack: ["jack"],
Jade: ["jade|pug"],
Java: ["java"],
JavaScript: ["js|jsm|cjs|mjs"],
JEXL: ["jexl"],
JSON: ["json"],
JSON5: ["json5"],
JSONiq: ["jq"],
JSP: ["jsp"],
JSSM: ["jssm|jssm_state"],
JSX: ["jsx"],
Julia: ["jl"],
Kotlin: ["kt|kts"],
LaTeX: ["tex|latex|ltx|bib"],
Latte: ["latte"],
LESS: ["less"],
Liquid: ["liquid"],
Lisp: ["lisp"],
LiveScript: ["ls"],
Log: ["log"],
LogiQL: ["logic|lql"],
Logtalk: ["lgt"],
LSL: ["lsl"],
Lua: ["lua"],
LuaPage: ["lp"],
Lucene: ["lucene"],
Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],
Markdown: ["md|markdown"],
Mask: ["mask"],
MATLAB: ["matlab"],
Maze: ["mz"],
MediaWiki: ["wiki|mediawiki"],
MEL: ["mel"],
MIPS: ["s|asm"],
MIXAL: ["mixal"],
MUSHCode: ["mc|mush"],
MySQL: ["mysql"],
Nasal: ["nas"],
Nginx: ["nginx|conf"],
Nim: ["nim"],
Nix: ["nix"],
NSIS: ["nsi|nsh"],
Nunjucks: ["nunjucks|nunjs|nj|njk"],
ObjectiveC: ["m|mm"],
OCaml: ["ml|mli"],
Odin: ["odin"],
PartiQL: ["partiql|pql"],
Pascal: ["pas|p"],
Perl: ["pl|pm"],
pgSQL: ["pgsql"],
PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],
PHP_Laravel_blade: ["blade.php"],
Pig: ["pig"],
PLSQL: ["plsql"],
Powershell: ["ps1"],
Praat: ["praat|praatscript|psc|proc"],
Prisma: ["prisma"],
Prolog: ["plg|prolog"],
Properties: ["properties"],
Protobuf: ["proto"],
PRQL: ["prql"],
Puppet: ["epp|pp"],
Python: ["py"],
QML: ["qml"],
R: ["r"],
Raku: ["raku|rakumod|rakutest|p6|pl6|pm6"],
Razor: ["cshtml|asp"],
RDoc: ["Rd"],
Red: ["red|reds"],
RHTML: ["Rhtml"],
Robot: ["robot|resource"],
RST: ["rst"],
Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],
Rust: ["rs"],
SaC: ["sac"],
SASS: ["sass"],
SCAD: ["scad"],
Scala: ["scala|sbt"],
Scheme: ["scm|sm|rkt|oak|scheme"],
Scrypt: ["scrypt"],
SCSS: ["scss"],
SH: ["sh|bash|^.bashrc"],
SJS: ["sjs"],
Slim: ["slim|skim"],
Smarty: ["smarty|tpl"],
Smithy: ["smithy"],
snippets: ["snippets"],
Soy_Template: ["soy"],
Space: ["space"],
SPARQL: ["rq"],
SQL: ["sql"],
SQLServer: ["sqlserver"],
Stylus: ["styl|stylus"],
SVG: ["svg"],
Swift: ["swift"],
Tcl: ["tcl"],
Terraform: ["tf", "tfvars", "terragrunt"],
Tex: ["tex"],
Text: ["txt"],
Textile: ["textile"],
Toml: ["toml"],
TSV: ["tsv"],
TSX: ["tsx"],
Turtle: ["ttl"],
Twig: ["twig|swig"],
Typescript: ["ts|mts|cts|typescript|str"],
Vala: ["vala"],
VBScript: ["vbs|vb"],
Velocity: ["vm"],
Verilog: ["v|vh|sv|svh"],
VHDL: ["vhd|vhdl"],
Visualforce: ["vfp|component|page"],
Vue: ["vue"],
Wollok: ["wlk|wpgm|wtest"],
XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],
XQuery: ["xq"],
YAML: ["yaml|yml"],
Zeek: ["zeek|bro"],
Zig: ["zig"]
};
var nameOverrides = {
ObjectiveC: "Objective-C",
CSharp: "C#",
golang: "Go",
C_Cpp: "C and C++",
Csound_Document: "Csound Document",
Csound_Orchestra: "Csound",
Csound_Score: "Csound Score",
coffee: "CoffeeScript",
HTML_Ruby: "HTML (Ruby)",
HTML_Elixir: "HTML (Elixir)",
FTL: "FreeMarker",
PHP_Laravel_blade: "PHP (Blade Template)",
Perl6: "Perl 6",
AutoHotKey: "AutoHotkey / AutoIt"
};
var modesByName = {};
for (var name in supportedModes) {
var data = supportedModes[name];
var displayName = (nameOverrides[name] || name).replace(/_/g, " ");
var filename = name.toLowerCase();
var mode = new Mode(filename, displayName, data[0]);
modesByName[filename] = mode;
modes.push(mode);
}
exports.getModeForPath = getModeForPath;
exports.modes = modes;
exports.modesByName = modesByName;
});
ace.define("ace/ext/themelist",["require","exports","module"], function(require, exports, module){/**
* ## Theme enumeration utility
*
* Provides theme management for the Ace Editor by generating and organizing available themes into
* categorized collections. Automatically maps theme data into structured objects containing theme metadata including
* display captions, theme paths, brightness classification (dark/light), and normalized names. Exports both an
* indexed theme collection and a complete themes array for easy integration with theme selection components
* and configuration systems.
*
* @author <a href="mailto:matthewkastor@gmail.com">
* Matthew Christopher Kastor-Inare III </a><br />
* @module
*/
"use strict";
var themeData = [
["Chrome"],
["Clouds"],
["Crimson Editor"],
["Dawn"],
["Dreamweaver"],
["Eclipse"],
["GitHub Light Default"],
["GitHub (Legacy)", "github", "light"],
["IPlastic"],
["Solarized Light"],
["TextMate"],
["Tomorrow"],
["XCode"],
["Kuroir"],
["KatzenMilch"],
["SQL Server", "sqlserver", "light"],
["CloudEditor", "cloud_editor", "light"],
["Ambiance", "ambiance", "dark"],
["Chaos", "chaos", "dark"],
["Clouds Midnight", "clouds_midnight", "dark"],
["Dracula", "", "dark"],
["Cobalt", "cobalt", "dark"],
["Gruvbox", "gruvbox", "dark"],
["Green on Black", "gob", "dark"],
["idle Fingers", "idle_fingers", "dark"],
["krTheme", "kr_theme", "dark"],
["Merbivore", "merbivore", "dark"],
["Merbivore Soft", "merbivore_soft", "dark"],
["Mono Industrial", "mono_industrial", "dark"],
["Monokai", "monokai", "dark"],
["Nord Dark", "nord_dark", "dark"],
["One Dark", "one_dark", "dark"],
["Pastel on dark", "pastel_on_dark", "dark"],
["Solarized Dark", "solarized_dark", "dark"],
["Terminal", "terminal", "dark"],
["Tomorrow Night", "tomorrow_night", "dark"],
["Tomorrow Night Blue", "tomorrow_night_blue", "dark"],
["Tomorrow Night Bright", "tomorrow_night_bright", "dark"],
["Tomorrow Night 80s", "tomorrow_night_eighties", "dark"],
["Twilight", "twilight", "dark"],
["Vibrant Ink", "vibrant_ink", "dark"],
["GitHub Dark", "github_dark", "dark"],
["CloudEditor Dark", "cloud_editor_dark", "dark"]
];
exports.themesByName = {};
exports.themes = themeData.map(function (data) {
var name = data[1] || data[0].replace(/ /g, "_").toLowerCase();
var theme = {
caption: data[0],
theme: "ace/theme/" + name,
isDark: data[2] == "dark",
name: name
};
exports.themesByName[name] = theme;
return theme;
});
});
ace.define("ace/ext/options",["require","exports","module","ace/ext/settings_menu","ace/ext/menu_tools/overlay_page","ace/lib/dom","ace/lib/oop","ace/config","ace/lib/event_emitter","ace/ext/modelist","ace/ext/themelist"], function(require, exports, module){/**
* ## Settings Menu extension
*
* Provides a settings panel for configuring editor options through an interactive UI.
* Creates a tabular interface with grouped configuration options including themes, modes, keybindings,
* font settings, display preferences, and advanced editor behaviors. Supports dynamic option rendering
* with various input types (dropdowns, checkboxes, number inputs, button bars) and real-time updates.
*
* **Usage:**
* ```javascript
* var OptionPanel = require("ace/ext/settings_menu").OptionPanel;
* var panel = new OptionPanel(editor);
* panel.render();
* ```
*
* @module
*/
"use strict";
require("./menu_tools/overlay_page");
var dom = require("../lib/dom");
var oop = require("../lib/oop");
var config = require("../config");
var EventEmitter = require("../lib/event_emitter").EventEmitter;
var buildDom = dom.buildDom;
var modelist = require("./modelist");
var themelist = require("./themelist");
var themes = { Bright: [], Dark: [] };
themelist.themes.forEach(function (x) {
themes[x.isDark ? "Dark" : "Bright"].push({ caption: x.caption, value: x.theme });
});
var modes = modelist.modes.map(function (x) {
return { caption: x.caption, value: x.mode };
});
var optionGroups = {
Main: {
Mode: {
path: "mode",
type: "select",
items: modes
},
Theme: {
path: "theme",
type: "select",
items: themes
},
"Keybinding": {
type: "buttonBar",
path: "keyboardHandler",
items: [
{ caption: "Ace", value: null },
{ caption: "Vim", value: "ace/keyboard/vim" },
{ caption: "Emacs", value: "ace/keyboard/emacs" },
{ caption: "Sublime", value: "ace/keyboard/sublime" },
{ caption: "VSCode", value: "ace/keyboard/vscode" }
]
},
"Font Size": {
path: "fontSize",
type: "number",
defaultValue: 12,
defaults: [
{ caption: "12px", value: 12 },
{ caption: "24px", value: 24 }
]
},
"Soft Wrap": {
type: "buttonBar",
path: "wrap",
items: [
{ caption: "Off", value: "off" },
{ caption: "View", value: "free" },
{ caption: "margin", value: "printMargin" },
{ caption: "40", value: "40" }
]
},
"Cursor Style": {
path: "cursorStyle",
items: [
{ caption: "Ace", value: "ace" },
{ caption: "Slim", value: "slim" },
{ caption: "Smooth", value: "smooth" },
{ caption: "Smooth And Slim", value: "smooth slim" },
{ caption: "Wide", value: "wide" }
]
},
"Folding": {
path: "foldStyle",
items: [
{ caption: "Manual", value: "manual" },
{ caption: "Mark begin", value: "markbegin" },
{ caption: "Mark begin and end", value: "markbeginend" }
]
},
"Soft Tabs": [{
path: "useSoftTabs"
}, {
ariaLabel: "Tab Size",
path: "tabSize",
type: "number",
values: [2, 3, 4, 8, 16]
}],
"Overscroll": {
type: "buttonBar",
path: "scrollPastEnd",
items: [
{ caption: "None", value: 0 },
{ caption: "Half", value: 0.5 },
{ caption: "Full", value: 1 }
]
}
},
More: {
"Atomic soft tabs": {
path: "navigateWithinSoftTabs"
},
"Enable Behaviours": {
path: "behavioursEnabled"
},
"Wrap with quotes": {
path: "wrapBehavioursEnabled"
},
"Enable Auto Indent": {
path: "enableAutoIndent"
},
"Full Line Selection": {
type: "checkbox",
values: "text|line",
path: "selectionStyle"
},
"Highlight Active Line": {
path: "highlightActiveLine"
},
"Show Invisibles": {
path: "showInvisibles"
},
"Show Indent Guides": {
path: "displayIndentGuides"
},
"Highlight Indent Guides": {
path: "highlightIndentGuides"
},
"Persistent HScrollbar": {
path: "hScrollBarAlwaysVisible"
},
"Persistent VScrollbar": {
path: "vScrollBarAlwaysVisible"
},
"Animate scrolling": {
path: "animatedScroll"
},
"Show Gutter": {
path: "showGutter"
},
"Show Line Numbers": {
path: "showLineNumbers"
},
"Relative Line Numbers": {
path: "relativeLineNumbers"
},
"Fixed Gutter Width": {
path: "fixedWidthGutter"
},
"Show Print Margin": [{
path: "showPrintMargin"
}, {
ariaLabel: "Print Margin",
type: "number",
path: "printMarginColumn"
}],
"Indented Soft Wrap": {
path: "indentedSoftWrap"
},
"Highlight selected word": {
path: "highlightSelectedWord"
},
"Fade Fold Widgets": {
path: "fadeFoldWidgets"
},
"Use textarea for IME": {
path: "useTextareaForIME"
},
"Merge Undo Deltas": {
path: "mergeUndoDeltas",
items: [
{ caption: "Always", value: "always" },
{ caption: "Never", value: "false" },
{ caption: "Timed", value: "true" }
]
},
"Elastic Tabstops": {
path: "useElasticTabstops"
},
"Incremental Search": {
path: "useIncrementalSearch"
},
"Read-only": {
path: "readOnly"
},
"Copy without selection": {
path: "copyWithEmptySelection"
},
"Live Autocompletion": {
path: "enableLiveAutocompletion"
},
"Custom scrollbar": {
path: "customScrollbar"
},
"Use SVG gutter icons": {
path: "useSvgGutterIcons"
},
"Annotations for folded lines": {
path: "showFoldedAnnotations"
},
"Keyboard Accessibility Mode": {
path: "enableKeyboardAccessibility"
},
"Gutter tooltip follows mouse": {
path: "tooltipFollowsMouse",
defaultValue: true
}
}
};
var OptionPanel = /** @class */ (function () {
function OptionPanel(editor, element) {
this.editor = editor;
this.container = element || document.createElement("div");
this.groups = [];
this.options = {};
}
OptionPanel.prototype.add = function (config) {
if (config.Main)
oop.mixin(optionGroups.Main, config.Main);
if (config.More)
oop.mixin(optionGroups.More, config.More);
};
OptionPanel.prototype.render = function () {
this.container.innerHTML = "";
buildDom(["table", { role: "presentation", id: "controls" },
this.renderOptionGroup(optionGroups.Main),
["tr", null, ["td", { colspan: 2 },
["table", { role: "presentation", id: "more-controls" },
this.renderOptionGroup(optionGroups.More)
]
]],
["tr", null, ["td", { colspan: 2 }, "version " + config.version]]
], this.container);
};
OptionPanel.prototype.renderOptionGroup = function (group) {
return Object.keys(group).map(function (key, i) {
var item = group[key];
if (!item.position)
item.position = i / 10000;
if (!item.label)
item.label = key;
return item;
}).sort(function (a, b) {
return a.position - b.position;
}).map(function (item) {
return this.renderOption(item.label, item);
}, this);
};
OptionPanel.prototype.renderOptionControl = function (key, option) {
var self = this;
if (Array.isArray(option)) {
return option.map(function (x) {
return self.renderOptionControl(key, x);
});
}
var control;
var value = self.getOption(option);
if (option.values && option.type != "checkbox") {
if (typeof option.values == "string")
option.values = option.values.split("|");
option.items = option.values.map(function (v) {
return { value: v, name: v };
});
}
if (option.type == "buttonBar") {
control = ["div", { role: "group", "aria-labelledby": option.path + "-label" }, option.items.map(function (item) {
return ["button", {
value: item.value,
ace_selected_button: value == item.value,
'aria-pressed': value == item.value,
onclick: function () {
self.setOption(option, item.value);
var nodes = this.parentNode.querySelectorAll("[ace_selected_button]");
for (var i = 0; i < nodes.length; i++) {
nodes[i].removeAttribute("ace_selected_button");
nodes[i].setAttribute("aria-pressed", false);
}
this.setAttribute("ace_selected_button", true);
this.setAttribute("aria-pressed", true);
}
}, item.desc || item.caption || item.name];
})];
}
else if (option.type == "number") {
control = ["input", { type: "number", value: value || option.defaultValue, style: "width:3em", oninput: function () {
self.setOption(option, parseInt(this.value));
} }];
if (option.ariaLabel) {
control[1]["aria-label"] = option.ariaLabel;
}
else {
control[1].id = key;
}
if (option.defaults) {
control = [control, option.defaults.map(function (item) {
return ["button", { onclick: function () {
var input = this.parentNode.firstChild;
input.value = item.value;
input.oninput();
} }, item.caption];
})];
}
}
else if (option.items) {
var buildItems = function (items) {
return items.map(function (item) {
return ["option", { value: item.value || item.name }, item.desc || item.caption || item.name];
});
};
var items = Array.isArray(option.items)
? buildItems(option.items)
: Object.keys(option.items).map(function (key) {
return ["optgroup", { "label": key }, buildItems(option.items[key])];
});
control = ["select", { id: key, value: value, onchange: function () {
self.setOption(option, this.value);
} }, items];
}
else {
if (typeof option.values == "string")
option.values = option.values.split("|");
if (option.values)
value = value == option.values[1];
control = ["input", { type: "checkbox", id: key, checked: value || null, onchange: function () {
var value = this.checked;
if (option.values)
value = option.values[value ? 1 : 0];
self.setOption(option, value);
} }];
if (option.type == "checkedNumber") {
control = [control, []];
}
}
return control;
};
OptionPanel.prototype.renderOption = function (key, option) {
if (option.path && !option.onchange && !this.editor.$options[option.path])
return;
var path = Array.isArray(option) ? option[0].path : option.path;
this.options[path] = option;
var safeKey = "-" + path;
var safeId = path + "-label";
var control = this.renderOptionControl(safeKey, option);
return ["tr", { class: "ace_optionsMenuEntry" }, ["td",
["label", { for: safeKey, id: safeId }, key]
], ["td", control]];
};
OptionPanel.prototype.setOption = function (option, value) {
if (typeof option == "string")
option = this.options[option];
if (value == "false")
value = false;
if (value == "true")
value = true;
if (value == "null")
value = null;
if (value == "undefined")
value = undefined;
if (typeof value == "string" && parseFloat(value).toString() == value)
value = parseFloat(value);
if (option.onchange)
option.onchange(value);
else if (option.path)
this.editor.setOption(option.path, value);
this._signal("setOption", { name: option.path, value: value });
};
OptionPanel.prototype.getOption = function (option) {
if (option.getValue)
return option.getValue();
return this.editor.getOption(option.path);
};
return OptionPanel;
}());
oop.implement(OptionPanel.prototype, EventEmitter);
exports.OptionPanel = OptionPanel;
exports.optionGroups = optionGroups;
});
ace.define("ace/ext/settings_menu",["require","exports","module","ace/ext/options","ace/ext/menu_tools/overlay_page","ace/editor"], function(require, exports, module){/**
* ## Interactive Settings Menu Extension
*
* Provides settings interface for the Ace editor that displays dynamically generated configuration options based on
* the current editor state. The menu appears as an overlay panel allowing users to modify editor options, themes,
* modes, and other settings through an intuitive graphical interface.
*
* **Usage:**
* ```javascript
* editor.showSettingsMenu();
* ```
*
* The extension automatically registers the `showSettingsMenu` command and method
* on the editor instance when initialized.
*
* @author <a href="mailto:matthewkastor@gmail.com">
* Matthew Christopher Kastor-Inare III </a><br />
*
* @module
*/
"use strict";
var OptionPanel = require("./options").OptionPanel;
var overlayPage = require('./menu_tools/overlay_page').overlayPage;
function showSettingsMenu(editor) {
if (!document.getElementById('ace_settingsmenu')) {
var options = new OptionPanel(editor);
options.render();
options.container.id = "ace_settingsmenu";
overlayPage(editor, options.container);
options.container.querySelector("select,input,button,checkbox").focus();
}
}
module.exports.init = function () {
var Editor = require("../editor").Editor;
Editor.prototype.showSettingsMenu = function () {
showSettingsMenu(this);
};
};
}); (function() {
ace.require(["ace/ext/settings_menu"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,137 @@
ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"], function(require, exports, module){"use strict";
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var JsonHighlightRules = function () {
this.$rules = {
"start": [
{
token: "variable", // single line
regex: '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)'
}, {
token: "string", // single line
regex: '"',
next: "string"
}, {
token: "constant.numeric", // hex
regex: "0[xX][0-9a-fA-F]+\\b"
}, {
token: "constant.numeric", // float
regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
}, {
token: "constant.language.boolean",
regex: "(?:true|false)\\b"
}, {
token: "text", // single quoted strings are not allowed
regex: "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"
}, {
token: "comment", // comments are not allowed, but who cares?
regex: "\\/\\/.*$"
}, {
token: "comment.start", // comments are not allowed, but who cares?
regex: "\\/\\*",
next: "comment"
}, {
token: "paren.lparen",
regex: "[[({]"
}, {
token: "paren.rparen",
regex: "[\\])}]"
}, {
token: "punctuation.operator",
regex: /[,]/
}, {
token: "text",
regex: "\\s+"
}
],
"string": [
{
token: "constant.language.escape",
regex: /\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/
}, {
token: "string",
regex: '"|$',
next: "start"
}, {
defaultToken: "string"
}
],
"comment": [
{
token: "comment.end", // comments are not allowed, but who cares?
regex: "\\*\\/",
next: "start"
}, {
defaultToken: "comment"
}
]
};
};
oop.inherits(JsonHighlightRules, TextHighlightRules);
exports.JsonHighlightRules = JsonHighlightRules;
});
ace.define("ace/ext/simple_tokenizer",["require","exports","module","ace/ext/simple_tokenizer","ace/mode/json_highlight_rules","ace/tokenizer","ace/layer/text_util"], function(require, exports, module){/**
* ## Simple tokenizer extension
*
* Provides standalone tokenization functionality that can parse code content using Ace's highlight rules without
* requiring a full editor instance. This is useful for generating syntax-highlighted tokens for external rendering,
* static code generation, or testing tokenization rules. The tokenizer processes text line by line and returns
* structured token data with CSS class names compatible with Ace themes.
*
* **Usage:**
* ```javascript
* const { tokenize } = require("ace/ext/simple_tokenizer");
* const { JsonHighlightRules } = require("ace/mode/json_highlight_rules");
*
* const content = '{"name": "value"}';
* const tokens = tokenize(content, new JsonHighlightRules());
* // Returns: [[{className: "ace_paren ace_lparen", value: "{"}, ...]]
* ```
*
* @module
*/
"use strict";
var Tokenizer = require("../tokenizer").Tokenizer;
var isTextToken = require("../layer/text_util").isTextToken;
var SimpleTokenizer = /** @class */ (function () {
function SimpleTokenizer(content, tokenizer) {
this._lines = content.split(/\r\n|\r|\n/);
this._states = [];
this._tokenizer = tokenizer;
}
SimpleTokenizer.prototype.getTokens = function (row) {
var line = this._lines[row];
var previousState = this._states[row - 1];
var data = this._tokenizer.getLineTokens(line, previousState);
this._states[row] = data.state;
return data.tokens;
};
SimpleTokenizer.prototype.getLength = function () {
return this._lines.length;
};
return SimpleTokenizer;
}());
function tokenize(content, highlightRules) {
var tokenizer = new SimpleTokenizer(content, new Tokenizer(highlightRules.getRules()));
var result = [];
for (var lineIndex = 0; lineIndex < tokenizer.getLength(); lineIndex++) {
var lineTokens = tokenizer.getTokens(lineIndex);
result.push(lineTokens.map(function (token) { return ({
className: isTextToken(token.type) ? undefined : "ace_" + token.type.replace(/\./g, " ace_"),
value: token.value
}); }));
}
return result;
}
exports.tokenize = tokenize;
}); (function() {
ace.require(["ace/ext/simple_tokenizer"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,79 @@
ace.define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"], function(require, exports, module){/**
* ## Browser spellcheck integration extension for native spelling correction
*
* Provides seamless integration with browser's native spellcheck functionality through context menu interactions.
* Enables right-click spelling suggestions on misspelled words while preserving editor functionality and text input
* handling. The extension bridges browser spellcheck capabilities with the editor's text manipulation system.
*
* **Enable:** `editor.setOption("spellcheck", true)` (enabled by default)
* or configure it during editor initialization in the options object.
*
* @module
*/
"use strict";
var event = require("../lib/event");
exports.contextMenuHandler = function (e) {
var host = e.target;
var text = host.textInput.getElement();
if (!host.selection.isEmpty())
return;
var c = host.getCursorPosition();
var r = host.session.getWordRange(c.row, c.column);
var w = host.session.getTextRange(r);
host.session.tokenRe.lastIndex = 0;
if (!host.session.tokenRe.test(w))
return;
var PLACEHOLDER = "\x01\x01";
var value = w + " " + PLACEHOLDER;
text.value = value;
text.setSelectionRange(w.length, w.length + 1);
text.setSelectionRange(0, 0);
text.setSelectionRange(0, w.length);
var afterKeydown = false;
event.addListener(text, "keydown", function onKeydown() {
event.removeListener(text, "keydown", onKeydown);
afterKeydown = true;
});
host.textInput.setInputHandler(function (newVal) {
if (newVal == value)
return '';
if (newVal.lastIndexOf(value, 0) === 0)
return newVal.slice(value.length);
if (newVal.substr(text.selectionEnd) == value)
return newVal.slice(0, -value.length);
if (newVal.slice(-2) == PLACEHOLDER) {
var val = newVal.slice(0, -2);
if (val.slice(-1) == " ") {
if (afterKeydown)
return val.substring(0, text.selectionEnd);
val = val.slice(0, -1);
host.session.replace(r, val);
return "";
}
}
return newVal;
});
};
var Editor = require("../editor").Editor;
require("../config").defineOptions(Editor.prototype, "editor", {
spellcheck: {
set: function (val) {
var text = this.textInput.getElement();
text.spellcheck = !!val;
if (!val)
this.removeListener("nativecontextmenu", exports.contextMenuHandler);
else
this.on("nativecontextmenu", exports.contextMenuHandler);
},
value: true
}
});
}); (function() {
ace.require(["ace/ext/spellcheck"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

View File

@ -0,0 +1,203 @@
ace.define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"], function(require, exports, module){"use strict";
var oop = require("./lib/oop");
var lang = require("./lib/lang");
var EventEmitter = require("./lib/event_emitter").EventEmitter;
var Editor = require("./editor").Editor;
var Renderer = require("./virtual_renderer").VirtualRenderer;
var EditSession = require("./edit_session").EditSession;
var Split;
Split = function (container, theme, splits) {
this.BELOW = 1;
this.BESIDE = 0;
this.$container = container;
this.$theme = theme;
this.$splits = 0;
this.$editorCSS = "";
this.$editors = [];
this.$orientation = this.BESIDE;
this.setSplits(splits || 1);
this.$cEditor = this.$editors[0];
this.on("focus", function (editor) {
this.$cEditor = editor;
}.bind(this));
};
(function () {
oop.implement(this, EventEmitter);
this.$createEditor = function () {
var el = document.createElement("div");
el.className = this.$editorCSS;
el.style.cssText = "position: absolute; top:0px; bottom:0px";
this.$container.appendChild(el);
var editor = new Editor(new Renderer(el, this.$theme));
editor.on("focus", function () {
this._emit("focus", editor);
}.bind(this));
this.$editors.push(editor);
editor.setFontSize(this.$fontSize);
return editor;
};
this.setSplits = function (splits) {
var editor;
if (splits < 1) {
throw "The number of splits have to be > 0!";
}
if (splits == this.$splits) {
return;
}
else if (splits > this.$splits) {
while (this.$splits < this.$editors.length && this.$splits < splits) {
editor = this.$editors[this.$splits];
this.$container.appendChild(editor.container);
editor.setFontSize(this.$fontSize);
this.$splits++;
}
while (this.$splits < splits) {
this.$createEditor();
this.$splits++;
}
}
else {
while (this.$splits > splits) {
editor = this.$editors[this.$splits - 1];
this.$container.removeChild(editor.container);
this.$splits--;
}
}
this.resize();
};
this.getSplits = function () {
return this.$splits;
};
this.getEditor = function (idx) {
return this.$editors[idx];
};
this.getCurrentEditor = function () {
return this.$cEditor;
};
this.focus = function () {
this.$cEditor.focus();
};
this.blur = function () {
this.$cEditor.blur();
};
this.setTheme = function (theme) {
this.$editors.forEach(function (editor) {
editor.setTheme(theme);
});
};
this.setKeyboardHandler = function (keybinding) {
this.$editors.forEach(function (editor) {
editor.setKeyboardHandler(keybinding);
});
};
this.forEach = function (callback, scope) {
this.$editors.forEach(callback, scope);
};
this.$fontSize = "";
this.setFontSize = function (size) {
this.$fontSize = size;
this.forEach(function (editor) {
editor.setFontSize(size);
});
};
this.$cloneSession = function (session) {
var s = new EditSession(session.getDocument(), session.getMode());
var undoManager = session.getUndoManager();
s.setUndoManager(undoManager);
s.setTabSize(session.getTabSize());
s.setUseSoftTabs(session.getUseSoftTabs());
s.setOverwrite(session.getOverwrite());
s.setBreakpoints(session.getBreakpoints());
s.setUseWrapMode(session.getUseWrapMode());
s.setUseWorker(session.getUseWorker());
s.setWrapLimitRange(session.$wrapLimitRange.min, session.$wrapLimitRange.max);
s.$foldData = session.$cloneFoldData();
return s;
};
this.setSession = function (session, idx) {
var editor;
if (idx == null) {
editor = this.$cEditor;
}
else {
editor = this.$editors[idx];
}
var isUsed = this.$editors.some(function (editor) {
return editor.session === session;
});
if (isUsed) {
session = this.$cloneSession(session);
}
editor.setSession(session);
return session;
};
this.getOrientation = function () {
return this.$orientation;
};
this.setOrientation = function (orientation) {
if (this.$orientation == orientation) {
return;
}
this.$orientation = orientation;
this.resize();
};
this.resize = function () {
var width = this.$container.clientWidth;
var height = this.$container.clientHeight;
var editor;
if (this.$orientation == this.BESIDE) {
var editorWidth = width / this.$splits;
for (var i = 0; i < this.$splits; i++) {
editor = this.$editors[i];
editor.container.style.width = editorWidth + "px";
editor.container.style.top = "0px";
editor.container.style.left = i * editorWidth + "px";
editor.container.style.height = height + "px";
editor.resize();
}
}
else {
var editorHeight = height / this.$splits;
for (var i = 0; i < this.$splits; i++) {
editor = this.$editors[i];
editor.container.style.width = width + "px";
editor.container.style.top = i * editorHeight + "px";
editor.container.style.left = "0px";
editor.container.style.height = editorHeight + "px";
editor.resize();
}
}
};
}).call(Split.prototype);
exports.Split = Split;
});
ace.define("ace/ext/split",["require","exports","module","ace/ext/split","ace/split"], function(require, exports, module){/**
* ## Split editor container extension for multiple editor instances
*
* Provides functionality to create and manage multiple editor instances within a single container,
* arranged either horizontally (beside) or vertically (below). Enables synchronized editing sessions
* with shared configurations while maintaining independent cursor positions and selections.
*
* **Usage:**
* ```javascript
* var Split = require("ace/ext/split").Split;
* var split = new Split(container, theme, numberOfSplits);
* split.setOrientation(split.BESIDE); // or split.BELOW
* ```
*
* @experimental
* @module
*/
"use strict";
module.exports = require("../split");
}); (function() {
ace.require(["ace/ext/split"], function(m) {
if (typeof module == "object" && typeof exports == "object" && module) {
module.exports = m;
}
});
})();

Some files were not shown because too many files have changed in this diff Show More