MonatKommit Februat
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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__/dss_screendesigner_controller.cpython-311.pyc
Executable file → Normal 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})
|
||||
|
||||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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())
|
||||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -52,4 +52,10 @@ width:90px;
|
|||
|
||||
min-width: 30px !important;
|
||||
|
||||
}
|
||||
|
||||
.dss_form_line {
|
||||
border-style: double;
|
||||
border-width: 1px;
|
||||
border-color:#B0B0B0
|
||||
}
|
||||
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 603 KiB |
|
After Width: | Height: | Size: 440 KiB |
|
After Width: | Height: | Size: 832 KiB |
|
After Width: | Height: | Size: 191 KiB |
|
After Width: | Height: | Size: 208 KiB |
|
After Width: | Height: | Size: 205 KiB |
|
After Width: | Height: | Size: 252 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 953 KiB |
|
After Width: | Height: | Size: 957 KiB |
|
After Width: | Height: | Size: 342 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 306 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
After Width: | Height: | Size: 556 KiB |
|
After Width: | Height: | Size: 453 KiB |
|
After Width: | Height: | Size: 562 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
|
@ -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 |
|
After Width: | Height: | Size: 9.6 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
; (function() {
|
||||
ace.require(["ace/ext/error_marker"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
; (function() {
|
||||
ace.require(["ace/ext/error_marker"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
; (function() {
|
||||
ace.require(["ace/ext/error_marker"], function(m) {
|
||||
if (typeof module == "object" && typeof exports == "object" && module) {
|
||||
module.exports = m;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||