UNPKG

@yelon/theme

Version:

ng-yunzai theme system library.

1,054 lines (1,043 loc) 154 kB
import { DOCUMENT, isPlatformServer, registerLocaleData, CommonModule } from '@angular/common'; import * as i0 from '@angular/core'; import { inject, PLATFORM_ID, InjectionToken, Injectable, DestroyRef, Injector, Pipe, Optional, SkipSelf, NgModule, importProvidersFrom, LOCALE_ID, provideEnvironmentInitializer, makeEnvironmentProviders, Version } from '@angular/core'; import { BehaviorSubject, filter, share, Subject, map, of, delay, isObservable, switchMap, tap, finalize, takeUntil, catchError, Observable, take, throwError } from 'rxjs'; import { ACLService } from '@yelon/acl'; import { YunzaiConfigService, YUNZAI_CONFIG } from '@yelon/util/config'; import { Platform } from '@angular/cdk/platform'; import { Directionality } from '@angular/cdk/bidi'; import { NzConfigService } from 'ng-zorro-antd/core/config'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import { Title, DomSanitizer } from '@angular/platform-browser'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import ngElGr from '@angular/common/locales/el'; import ngEn from '@angular/common/locales/en'; import ngEsEs from '@angular/common/locales/es'; import ngFr from '@angular/common/locales/fr'; import ngHr from '@angular/common/locales/hr'; import ngIt from '@angular/common/locales/it'; import ngKo from '@angular/common/locales/ko'; import ngPl from '@angular/common/locales/pl'; import ngSl from '@angular/common/locales/sl'; import ngTr from '@angular/common/locales/tr'; import ngZh from '@angular/common/locales/zh'; import ngZhTw from '@angular/common/locales/zh-Hant'; import { tr, sl, pl, ko, it, hr, fr, es, el, enUS, zhTW, zhCN as zhCN$1 } from 'date-fns/locale'; import { tr_TR, sl_SI, pl_PL, ko_KR, it_IT, hr_HR, fr_FR, es_ES, el_GR, en_US, zh_TW, zh_CN, NzI18nService, NzI18nModule, provideNzI18n, NZ_DATE_LOCALE } from 'ng-zorro-antd/i18n'; import { map as map$1 } from 'rxjs/operators'; import { YA_SERVICE_TOKEN } from '@yelon/auth'; import { HttpClient, HttpParams, HttpContextToken } from '@angular/common/http'; import { DragDrop } from '@angular/cdk/drag-drop'; import { SIGNAL } from '@angular/core/primitives/signals'; import { deepMerge } from '@yelon/util/other'; import { NzModalService, NzModalModule } from 'ng-zorro-antd/modal'; import { NzDrawerService, NzDrawerModule } from 'ng-zorro-antd/drawer'; import { formatDate } from '@yelon/util/date-time'; import { OverlayModule } from '@angular/cdk/overlay'; import { AccountBookTwoTone, AccountBookFill, AccountBookOutline, AlertTwoTone, AlertFill, AlibabaOutline, AimOutline, AlipayCircleFill, AlertOutline, AlignCenterOutline, AlipayCircleOutline, AlipayOutline, AlignLeftOutline, AlignRightOutline, AmazonOutline, AliwangwangOutline, AliyunOutline, AlipaySquareFill, AmazonCircleFill, AndroidFill, AliwangwangFill, AntCloudOutline, AmazonSquareFill, AndroidOutline, ApartmentOutline, ApiTwoTone, ApiFill, ApiOutline, AntDesignOutline, AppstoreAddOutline, AppstoreFill, AppleOutline, AppstoreOutline, ArrowDownOutline, AppleFill, ArrowsAltOutline, AppstoreTwoTone, ArrowUpOutline, AreaChartOutline, ArrowLeftOutline, AudioFill, ArrowRightOutline, AudioTwoTone, AuditOutline, AudioMutedOutline, BackwardFill, AudioOutline, BackwardOutline, BankFill, BarcodeOutline, BellFill, BankTwoTone, BarsOutline, BankOutline, BehanceCircleFill, BehanceSquareFill, BoldOutline, BellOutline, BehanceOutline, BlockOutline, BehanceSquareOutline, BgColorsOutline, BellTwoTone, BarChartOutline, BookTwoTone, BookFill, BorderOuterOutline, BorderLeftOutline, BorderBottomOutline, BorderHorizontalOutline, BorderTopOutline, BorderOutline, BorderInnerOutline, BorderRightOutline, BoxPlotOutline, BoxPlotFill, BoxPlotTwoTone, BookOutline, BorderlessTableOutline, BorderVerticleOutline, BuildTwoTone, BuildOutline, BugFill, BugOutline, BugTwoTone, BulbFill, BulbTwoTone, BuildFill, BulbOutline, CalculatorFill, CalculatorTwoTone, CalendarFill, CalendarOutline, CalculatorOutline, CalendarTwoTone, CameraOutline, CameraFill, CameraTwoTone, CarTwoTone, CaretDownOutline, CarOutline, CaretLeftFill, CarFill, CaretRightOutline, CaretDownFill, CaretUpOutline, CaretRightFill, CarryOutFill, CarryOutOutline, CaretLeftOutline, CaretUpFill, BranchesOutline, CarryOutTwoTone, CheckCircleFill, CheckCircleOutline, CheckSquareOutline, CheckCircleTwoTone, CiCircleTwoTone, CheckOutline, CheckSquareTwoTone, CiOutline, CheckSquareFill, CiTwoTone, ChromeOutline, ClockCircleOutline, CiCircleOutline, ChromeFill, ClearOutline, CloseCircleTwoTone, CiCircleFill, CloseCircleOutline, ClockCircleFill, CloseCircleFill, ClockCircleTwoTone, CloseOutline, CloseSquareOutline, CloseSquareFill, CloudFill, CloseSquareTwoTone, CloudDownloadOutline, CloudTwoTone, CloudServerOutline, CloudUploadOutline, CloudSyncOutline, ClusterOutline, CodeSandboxCircleFill, CodeFill, CodepenCircleOutline, CloudOutline, CodeSandboxOutline, CodeOutline, CodeSandboxSquareFill, CodeTwoTone, CodepenSquareFill, CodepenOutline, CoffeeOutline, ColumnWidthOutline, CompressOutline, ColumnHeightOutline, CodepenCircleFill, CompassTwoTone, CommentOutline, ContainerFill, CompassOutline, ConsoleSqlOutline, ContactsOutline, ContainerTwoTone, ContactsFill, ContactsTwoTone, ContainerOutline, ControlFill, CopyFill, CopyOutline, CompassFill, CopyTwoTone, CopyrightOutline, CopyrightCircleOutline, ControlTwoTone, ControlOutline, CreditCardFill, CopyrightTwoTone, CrownFill, CopyrightCircleFill, CrownOutline, CustomerServiceTwoTone, CreditCardOutline, CustomerServiceOutline, DashboardTwoTone, CrownTwoTone, CreditCardTwoTone, CustomerServiceFill, DashboardFill, DashOutline, DatabaseOutline, DatabaseTwoTone, DatabaseFill, DashboardOutline, DeleteTwoTone, DeleteRowOutline, DeleteColumnOutline, DeliveredProcedureOutline, DeleteOutline, CopyrightCircleTwoTone, DesktopOutline, DeleteFill, DiffOutline, DiffFill, DeploymentUnitOutline, DiffTwoTone, DingtalkOutline, DollarCircleFill, DislikeFill, DingtalkSquareFill, DisconnectOutline, DollarCircleTwoTone, DollarOutline, DingtalkCircleFill, DislikeTwoTone, DollarTwoTone, DownCircleFill, DislikeOutline, DollarCircleOutline, DoubleLeftOutline, DownSquareFill, DownOutline, DownSquareOutline, DownSquareTwoTone, DownCircleTwoTone, DoubleRightOutline, DownCircleOutline, DownloadOutline, DotChartOutline, DribbbleCircleFill, DribbbleOutline, DribbbleSquareOutline, DropboxCircleFill, DingdingOutline, EditOutline, DribbbleSquareFill, DropboxSquareFill, EllipsisOutline, EnvironmentFill, EditFill, EnterOutline, EuroCircleFill, EuroTwoTone, EuroCircleOutline, EditTwoTone, EuroOutline, EnvironmentTwoTone, ExclamationCircleFill, ExpandAltOutline, EuroCircleTwoTone, ExclamationCircleTwoTone, EnvironmentOutline, ExperimentOutline, ExperimentFill, ExpandOutline, ExceptionOutline, ExportOutline, ExperimentTwoTone, ExclamationCircleOutline, ExclamationOutline, EyeFill, EyeInvisibleFill, EyeInvisibleTwoTone, DropboxOutline, DragOutline, FacebookOutline, FacebookFill, EyeTwoTone, EyeOutline, FastForwardFill, FieldBinaryOutline, FieldNumberOutline, FastBackwardOutline, FileAddFill, FastBackwardFill, FileExcelFill, FastForwardOutline, FieldStringOutline, FileDoneOutline, FileAddTwoTone, FileExcelTwoTone, FileExclamationFill, FileAddOutline, FileExclamationOutline, FieldTimeOutline, FileImageTwoTone, FileExcelOutline, FileExclamationTwoTone, FileImageFill, FileGifOutline, FileFill, FileMarkdownTwoTone, FileMarkdownOutline, FallOutline, FileImageOutline, EyeInvisibleOutline, FilePdfOutline, FileSearchOutline, FilePptTwoTone, FilePdfTwoTone, FileJpgOutline, FileTextFill, FilePptOutline, FileSyncOutline, FilePptFill, FileUnknownOutline, FileProtectOutline, FileTextTwoTone, FileWordFill, FileUnknownTwoTone, FileWordTwoTone, FileUnknownFill, FileTextOutline, FileZipFill, FilterTwoTone, FilterFill, FileWordOutline, FireOutline, FireTwoTone, FileZipOutline, FilterOutline, FlagTwoTone, FileTwoTone, FilePdfFill, FileOutline, FileMarkdownFill, FileZipTwoTone, FlagOutline, FolderAddTwoTone, FolderOpenFill, FireFill, FlagFill, FolderOutline, FolderViewOutline, FolderTwoTone, FontColorsOutline, FolderOpenTwoTone, FolderFill, ForwardOutline, FolderOpenOutline, ForkOutline, ForwardFill, FormatPainterOutline, FormatPainterFill, FormOutline, FrownFill, FrownTwoTone, FullscreenOutline, FontSizeOutline, FundFill, FunctionOutline, FundViewOutline, FullscreenExitOutline, GifOutline, FundProjectionScreenOutline, FundTwoTone, FolderAddFill, FunnelPlotTwoTone, GiftOutline, FunnelPlotFill, FundOutline, FrownOutline, GithubOutline, GoldFill, FolderAddOutline, GitlabFill, GiftFill, GitlabOutline, GoldTwoTone, GoogleCircleFill, GiftTwoTone, GooglePlusCircleFill, GoldOutline, GithubFill, GoogleOutline, GooglePlusOutline, GoogleSquareFill, GoldenFill, HddTwoTone, GooglePlusSquareFill, GlobalOutline, HeartOutline, HeartTwoTone, GroupOutline, HeartFill, HeatMapOutline, GatewayOutline, FunnelPlotOutline, HddFill, HomeFill, HighlightFill, HomeOutline, HistoryOutline, HighlightOutline, HddOutline, HourglassFill, HomeTwoTone, HourglassTwoTone, Html5Outline, Html5Fill, IdcardFill, Html5TwoTone, HourglassOutline, IdcardTwoTone, IdcardOutline, IeOutline, IeCircleFill, IeSquareFill, InboxOutline, ImportOutline, InfoCircleOutline, InfoCircleTwoTone, InsertRowAboveOutline, InsertRowRightOutline, InfoCircleFill, InfoOutline, InsertRowBelowOutline, HighlightTwoTone, InsuranceFill, InstagramFill, InteractionFill, InsertRowLeftOutline, InstagramOutline, InteractionOutline, ItalicOutline, InteractionTwoTone, LayoutOutline, IssuesCloseOutline, LayoutFill, LaptopOutline, LeftCircleFill, LayoutTwoTone, KeyOutline, LeftOutline, LeftCircleOutline, LeftSquareOutline, LeftSquareFill, LeftCircleTwoTone, LikeFill, LeftSquareTwoTone, LineOutline, LikeTwoTone, LinkedinOutline, LineChartOutline, LineHeightOutline, LinkedinFill, LinkOutline, LikeOutline, InsuranceOutline, Loading3QuartersOutline, LockFill, InsuranceTwoTone, MacCommandOutline, LockTwoTone, LoadingOutline, MailOutline, LoginOutline, MedicineBoxOutline, MailFill, MailTwoTone, MacCommandFill, ManOutline, MedicineBoxFill, MedicineBoxTwoTone, MediumCircleFill, MediumOutline, MehFill, MediumWorkmarkOutline, MenuFoldOutline, MehOutline, MediumSquareFill, MessageTwoTone, MehTwoTone, MergeCellsOutline, MinusCircleFill, MenuOutline, MenuUnfoldOutline, MessageFill, MinusCircleTwoTone, LockOutline, MinusOutline, MinusCircleOutline, LogoutOutline, MessageOutline, MoneyCollectFill, MinusSquareOutline, MinusSquareTwoTone, MobileOutline, MobileTwoTone, MoneyCollectOutline, MoreOutline, NotificationFill, NotificationOutline, MoneyCollectTwoTone, NodeIndexOutline, NodeExpandOutline, MonitorOutline, OrderedListOutline, NodeCollapseOutline, NumberOutline, PaperClipOutline, NotificationTwoTone, PauseCircleFill, PartitionOutline, PauseOutline, OneToOneOutline, PayCircleOutline, PayCircleFill, MinusSquareFill, PauseCircleOutline, PauseCircleTwoTone, PicCenterOutline, PicRightOutline, PercentageOutline, MobileFill, PictureOutline, PictureFill, PhoneTwoTone, PhoneFill, PieChartFill, PictureTwoTone, PieChartOutline, PlaySquareFill, PlayCircleTwoTone, PlayCircleFill, PlusCircleFill, PlaySquareTwoTone, PlaySquareOutline, PlayCircleOutline, PieChartTwoTone, PlusCircleOutline, PlusSquareFill, PoundCircleFill, PlusSquareOutline, PlusOutline, PoundOutline, PoundCircleOutline, PlusSquareTwoTone, PlusCircleTwoTone, PoweroffOutline, PoundCircleTwoTone, PhoneOutline, PrinterFill, PicLeftOutline, ProjectTwoTone, PrinterOutline, ProjectFill, ProfileOutline, ProfileTwoTone, ProjectOutline, PropertySafetyFill, PullRequestOutline, PropertySafetyOutline, PushpinOutline, PushpinTwoTone, PropertySafetyTwoTone, PushpinFill, QqOutline, QqCircleFill, QrcodeOutline, QqSquareFill, QuestionCircleTwoTone, QuestionCircleFill, RadarChartOutline, RadiusUprightOutline, QuestionCircleOutline, QuestionOutline, ReadFill, RadiusUpleftOutline, RadiusBottomleftOutline, RadiusSettingOutline, RadiusBottomrightOutline, ProfileFill, PrinterTwoTone, ReadOutline, ReconciliationFill, ReloadOutline, ReconciliationOutline, RedEnvelopeTwoTone, RedditCircleFill, RedoOutline, RedEnvelopeFill, RedditOutline, RestTwoTone, RightCircleOutline, RestOutline, RedditSquareFill, RestFill, RightCircleTwoTone, RightOutline, RightSquareFill, RightCircleFill, RightSquareOutline, RetweetOutline, RiseOutline, RightSquareTwoTone, RobotFill, RocketOutline, RobotOutline, RocketTwoTone, RocketFill, RedEnvelopeOutline, RollbackOutline, RotateRightOutline, RotateLeftOutline, ReconciliationTwoTone, SafetyCertificateTwoTone, SaveOutline, SafetyOutline, SaveFill, SaveTwoTone, ScheduleFill, SafetyCertificateOutline, ScanOutline, ScheduleTwoTone, SearchOutline, ScheduleOutline, SecurityScanTwoTone, SecurityScanOutline, ScissorOutline, SelectOutline, SecurityScanFill, SendOutline, SettingOutline, SettingTwoTone, SettingFill, ShareAltOutline, ShopOutline, ShopFill, ShopTwoTone, ShrinkOutline, ShakeOutline, ShoppingOutline, ShoppingCartOutline, ShoppingFill, SisternodeOutline, ShoppingTwoTone, SafetyCertificateFill, SkinOutline, SignalFill, SketchOutline, SkinTwoTone, SketchSquareFill, SkypeFill, SkinFill, SlackCircleFill, SlackSquareFill, SlidersTwoTone, SkypeOutline, SlidersFill, SlackSquareOutline, SmallDashOutline, SmileTwoTone, SlidersOutline, SnippetsFill, SnippetsOutline, SmileOutline, SolutionOutline, SlackOutline, SnippetsTwoTone, SoundTwoTone, SortAscendingOutline, SoundFill, SortDescendingOutline, SmileFill, SoundOutline, SplitCellsOutline, SketchCircleFill, StarOutline, StockOutline, StarTwoTone, StepForwardFill, StarFill, StepBackwardFill, StepForwardOutline, StopFill, SubnodeOutline, SwapLeftOutline, StopOutline, StopTwoTone, SwapRightOutline, SwapOutline, SwitcherTwoTone, SwitcherOutline, SyncOutline, StrikethroughOutline, SwitcherFill, TagOutline, TabletTwoTone, TabletOutline, TabletFill, TableOutline, TagsFill, TagFill, TagsTwoTone, TaobaoCircleOutline, StepBackwardOutline, TagsOutline, TagTwoTone, TaobaoOutline, ThunderboltOutline, TaobaoSquareFill, TeamOutline, TaobaoCircleFill, ThunderboltTwoTone, ToolFill, ThunderboltFill, ToTopOutline, ToolOutline, ToolTwoTone, TrademarkCircleFill, TrophyFill, TrademarkCircleTwoTone, TransactionOutline, TrademarkCircleOutline, TranslationOutline, TwitterCircleFill, TrophyOutline, TrademarkOutline, TrophyTwoTone, TwitterSquareFill, UnlockFill, TwitterOutline, UnderlineOutline, UndoOutline, UpCircleFill, UngroupOutline, UnlockTwoTone, UnlockOutline, UpOutline, UsbFill, UpCircleOutline, UnorderedListOutline, UpCircleTwoTone, UpSquareFill, UpSquareOutline, UserAddOutline, UsbTwoTone, UsergroupDeleteOutline, UpSquareTwoTone, UserOutline, UsbOutline, UserDeleteOutline, UserSwitchOutline, VerticalLeftOutline, VerticalAlignBottomOutline, VerifiedOutline, UsergroupAddOutline, UploadOutline, VerticalAlignMiddleOutline, VerticalAlignTopOutline, VerticalRightOutline, VideoCameraOutline, VideoCameraAddOutline, VideoCameraTwoTone, VideoCameraFill, WalletOutline, WalletFill, WarningFill, WarningOutline, WechatOutline, WalletTwoTone, WeiboCircleFill, WarningTwoTone, WeiboSquareFill, WeiboOutline, WeiboSquareOutline, WeiboCircleOutline, WechatFill, WhatsAppOutline, WifiOutline, WomanOutline, YoutubeFill, YahooOutline, WindowsFill, WindowsOutline, YoutubeOutline, YuqueOutline, ZhihuCircleFill, YuqueFill, ZhihuOutline, ZhihuSquareFill, ZoomInOutline, ZoomOutOutline, YahooFill } from '@ant-design/icons-angular/icons'; import * as i1 from 'ng-zorro-antd/icon'; import { NzIconService } from 'ng-zorro-antd/icon'; function stepPreloader() { const doc = inject(DOCUMENT); const ssr = isPlatformServer(inject(PLATFORM_ID)); if (ssr) { return () => { }; } const body = doc.querySelector('body'); body.style.overflow = 'hidden'; let done = false; return () => { if (done) return; done = true; const preloader = doc.querySelector('.preloader'); if (preloader == null) return; const CLS = 'preloader-hidden'; preloader.addEventListener('transitionend', () => { preloader.className = CLS; }); preloader.className += ` ${CLS}-add ${CLS}-add-active`; body.style.overflow = ''; }; } const YUNZAI_I18N_TOKEN = new InjectionToken('yunzaiI18nToken', { providedIn: 'root', factory: () => new YunzaiI18NServiceFake() }); class YunzaiI18nBaseService { cogSrv = inject(YunzaiConfigService); cog; _change$ = new BehaviorSubject(null); _currentLang = ''; _defaultLang = ''; _data = {}; get change() { return this._change$.asObservable().pipe(filter(w => w != null)); } get defaultLang() { return this._defaultLang; } get currentLang() { return this._currentLang; } get data() { return this._data; } constructor() { this.cog = this.cogSrv.merge('themeI18n', { interpolation: ['{{', '}}'] }); } /** * Flattened data source * * @example * { * "name": "Name", * "sys": { * "": "System", * "title": "Title" * } * } * => * { * "name": "Name", * "sys": "System", * "sys.title": "Title" * } */ flatData(data, parentKey) { const res = {}; for (const key of Object.keys(data)) { const value = data[key]; if (typeof value === 'object') { const child = this.flatData(value, parentKey.concat(key)); Object.keys(child).forEach(childKey => (res[childKey] = child[childKey])); } else { res[(key ? parentKey.concat(key) : parentKey).join('.')] = `${value}`; } } return res; } fanyi(path, params) { let content = this._data[path] || ''; if (!content) return path; if (!params) return content; if (typeof params === 'object') { const interpolation = this.cog.interpolation; const objParams = params; Object.keys(objParams).forEach(key => { content = content.replace(new RegExp(`${interpolation[0]}\\s?${key}\\s?${interpolation[1]}`, 'g'), `${objParams[key]}`); }); } (Array.isArray(params) ? params : [params]).forEach((item, index) => (content = content.replace(new RegExp(`\\{\\s?${index}\\s?\\}`, 'g'), `${item}`))); return content; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18nBaseService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18nBaseService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18nBaseService, decorators: [{ type: Injectable }], ctorParameters: () => [] }); class YunzaiI18NServiceFake extends YunzaiI18nBaseService { use(lang, data) { this._data = this.flatData(data ?? {}, []); this._currentLang = lang; this._change$.next(lang); } getLangs() { return []; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18NServiceFake, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18NServiceFake, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18NServiceFake, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * 菜单服务,[在线文档](https://ng.yunzainfo.com/theme/menu) */ class MenuService { i18nSrv = inject(YUNZAI_I18N_TOKEN); aclService = inject(ACLService); _change$ = new BehaviorSubject([]); i18n$; data = []; $routerLink = new BehaviorSubject(''); /** * 是否完全受控菜单打开状态,默认:`false` */ openStrictly = false; constructor() { this.i18n$ = this.i18nSrv.change.subscribe(() => this.resume()); } get change() { return this._change$.pipe(share()); } get menus() { return this.data; } /** * Returns a default menu link * * 返回一个默认跳转的菜单链接 */ getDefaultRedirect(opt = {}) { let ret; this.visit(this.menus, (item) => { if (typeof item.link !== 'string' || item.link.length <= 0 || !item._aclResult || item._hidden === true) { return; } if (ret == null || ret.length <= 0 || item.link == opt?.redirectUrl) { ret = item.link; } }); return ret; } visit(data, callback) { const inFn = (list, parentMenu, depth) => { for (const item of list) { callback(item, parentMenu, depth); if (item.children && item.children.length > 0) { inFn(item.children, item, depth + 1); } else { item.children = []; } } }; inFn(data, null, 0); } add(items) { this.data = items; this.resume(); } fixItem(item) { item._aclResult = true; if (!item.render_type) item.render_type = 'item'; if (!item.link) item.link = ''; if (!item.externalLink) item.externalLink = ''; // badge if (item.badge) { if (item.badgeDot !== true) { item.badgeDot = false; } if (!item.badgeStatus) { item.badgeStatus = 'error'; } } if (!Array.isArray(item.children)) { item.children = []; } // icon if (typeof item.icon === 'string') { let type = 'class'; let value = item.icon; // compatible `anticon anticon-user` if (~item.icon.indexOf(`anticon-`)) { type = 'icon'; value = value.split('-').slice(1).join('-'); } else if (/^https?:\/\//.test(item.icon)) { type = 'img'; } item.icon = { type, value }; } if (item.icon != null) { item.icon = { theme: 'outline', spin: false, ...item.icon }; } item.text = item.i18n ? this.i18nSrv.fanyi(item.i18n) : item.text; // group item.group = item.group !== false; // hidden item._hidden = typeof item.hide === 'undefined' ? false : item.hide; // disabled item.disabled = typeof item.disabled === 'undefined' ? false : item.disabled; // acl item._aclResult = item.acl ? this.aclService.can(item.acl) : true; item.open = item.open != null ? item.open : false; } resume(callback) { let i = 1; const shortcuts = []; this.visit(this.data, (item, parent, depth) => { item._id = i++; item._parent = parent; item._depth = depth; this.fixItem(item); // shortcut if (parent && item.shortcut === true && parent.shortcutRoot !== true) { shortcuts.push(item); } if (callback) callback(item, parent, depth); }); this.loadShortcut(shortcuts); this._change$.next(this.data); } /** * 加载快捷菜单,加载位置规则如下: * 1、统一在下标0的节点下(即【主导航】节点下方) * 1、若 children 存在 【shortcutRoot: true】则最优先【推荐】这种方式 * 2、否则查找带有【dashboard】字样链接,若存在则在此菜单的下方创建快捷入口 * 3、否则放在0节点位置 */ loadShortcut(shortcuts) { if (shortcuts.length === 0 || this.data.length === 0) { return; } const ls = this.data[0].children; let pos = ls.findIndex(w => w.shortcutRoot === true); if (pos === -1) { pos = ls.findIndex(w => w.link.includes('dashboard')); pos = (pos !== -1 ? pos : -1) + 1; const shortcutMenu = { text: '快捷菜单', i18n: 'shortcut', icon: 'icon-rocket', children: [] }; this.data[0].children.splice(pos, 0, shortcutMenu); } let _data = this.data[0].children[pos]; if (_data.i18n) _data.text = this.i18nSrv.fanyi(_data.i18n); _data = Object.assign(_data, { shortcutRoot: true, _id: -1, _parent: null, _depth: 1 }); _data.children = shortcuts.map(i => { i._depth = 2; i._parent = _data; return i; }); } /** * 清空菜单 */ clear() { this.data = []; this._change$.next(this.data); } /** * Use `url` or `key` to find menus * * 利用 `url` 或 `key` 查找菜单 */ find(options) { const opt = { recursive: false, ignoreHide: false, last: false, ...options }; if (opt.key != null) { return this.getItem(opt.key); } let url = opt.url; let item = null; while (!item && url) { this.visit(opt.data ?? this.data, i => { if (!opt.last && item != null) { return; } if (opt.ignoreHide && i.hide) { return; } if (opt.cb) { const res = opt.cb(i); if (typeof res === 'boolean' && res) { item = i; } } if (i.link != null && i.link === url) { item = i; } }); if (!opt.recursive) break; if (/[?;]/g.test(url)) { url = url.split(/[?;]/g)[0]; } else { url = url.split('/').slice(0, -1).join('/'); } } return item; } /** * 根据url获取菜单列表 * - 若 `recursive: true` 则会自动向上递归查找 * - 菜单数据源包含 `/ware`,则 `/ware/1` 也视为 `/ware` 项 */ getPathByUrl(url, recursive = false) { const ret = []; let item = this.find({ url, recursive }); if (!item) return ret; do { ret.splice(0, 0, item); item = item._parent; } while (item); return ret; } /** * Get menu based on `key` */ getItem(key) { let res = null; this.visit(this.data, item => { if (res == null && item.key === key) { res = item; } }); return res; } /** * Set menu based on `key` */ setItem(key, value, options) { const item = typeof key === 'string' ? this.getItem(key) : key; if (item == null) return; Object.keys(value).forEach(k => { item[k] = value[k]; }); this.fixItem(item); if (options?.emit !== false) this._change$.next(this.data); } /** * Open menu based on `key` or menu object */ open(keyOrItem, options) { let item = typeof keyOrItem === 'string' ? this.find({ key: keyOrItem }) : keyOrItem; if (item == null) return; this.visit(this.menus, (i) => { i._selected = false; if (!this.openStrictly) i.open = false; }); do { item._selected = true; item.open = true; item = item._parent; } while (item); if (options?.emit !== false) this._change$.next(this.data); } openAll(status) { this.toggleOpen(null, { allStatus: status }); } toggleOpen(keyOrItem, options) { let item = typeof keyOrItem === 'string' ? this.find({ key: keyOrItem }) : keyOrItem; if (item == null) { this.visit(this.menus, (i) => { i._selected = false; i.open = options?.allStatus === true; }); } else { if (!this.openStrictly) { this.visit(this.menus, (i) => { if (i !== item) i.open = false; }); let pItem = item._parent; while (pItem) { pItem.open = true; pItem = pItem._parent; } } item.open = !item.open; } if (options?.emit !== false) this._change$.next(this.data); } ngOnDestroy() { this._change$.unsubscribe(); this.i18n$?.unsubscribe(); } setRouterLink(url) { this.$routerLink.next(url); } getRouterLink() { return this.$routerLink.asObservable(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MenuService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MenuService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [] }); const YUNZAI_SETTING_KEYS = new InjectionToken('YUNZAI_SETTING_KEYS'); const YUNZAI_SETTING_DEFAULT = { provide: YUNZAI_SETTING_KEYS, useValue: { layout: 'layout', user: 'user', app: 'app' } }; class SettingsService { KEYS = inject(YUNZAI_SETTING_KEYS); platform = inject(Platform); notify$ = new Subject(); _app = null; _user = null; _layout = null; getData(key) { if (!this.platform.isBrowser) { return null; } return JSON.parse(localStorage.getItem(key) || 'null') || null; } setData(key, value) { if (!this.platform.isBrowser) { return; } localStorage.setItem(key, JSON.stringify(value)); } get layout() { if (!this._layout) { this._layout = { fixed: true, collapsed: false, boxed: false, lang: null, ...this.getData(this.KEYS.layout) }; this.setData(this.KEYS.layout, this._layout); } return this._layout; } get app() { if (!this._app) { this._app = { year: new Date().getFullYear(), ...this.getData(this.KEYS.app) }; this.setData(this.KEYS.app, this._app); } return this._app; } get user() { if (!this._user) { this._user = { ...this.getData(this.KEYS.user) }; this.setData(this.KEYS.user, this._user); } return this._user; } get notify() { return this.notify$.asObservable(); } setLayout(name, value) { if (typeof name === 'string') { this.layout[name] = value; } else { this._layout = name; } this.setData(this.KEYS.layout, this._layout); this.notify$.next({ type: 'layout', name, value }); return true; } getLayout() { return this._layout; } setApp(value) { this._app = value; this.setData(this.KEYS.app, value); this.notify$.next({ type: 'app', value }); } getApp() { return this._app; } setUser(value) { this._user = value; this.setData(this.KEYS.user, value); this.notify$.next({ type: 'user', value }); } getUser() { return this._user; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: SettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: SettingsService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: SettingsService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); const REP_MAX = 6; const SPAN_MAX = 24; class ResponsiveService { cogSrv = inject(YunzaiConfigService); cog; constructor() { this.cog = this.cogSrv.merge('themeResponsive', { rules: { 1: { xs: 24 }, 2: { xs: 24, sm: 12 }, 3: { xs: 24, sm: 12, md: 8 }, 4: { xs: 24, sm: 12, md: 8, lg: 6 }, 5: { xs: 24, sm: 12, md: 8, lg: 6, xl: 4 }, 6: { xs: 24, sm: 12, md: 8, lg: 6, xl: 4, xxl: 2 } } }); if (Object.keys(this.cog.rules) .map(i => +i) .some((i) => i < 1 || i > REP_MAX)) { throw new Error(`[theme] the responseive rule index value range must be 1-${REP_MAX}`); } } genCls(count, defaultCol = 1) { const rule = { ...this.cog.rules[count > REP_MAX ? REP_MAX : Math.max(count, 1)] }; const antColClass = 'ant-col'; const itemMaxSpan = SPAN_MAX / defaultCol; const paddingSpan = (value) => { if (value == null || defaultCol <= 1 || count >= defaultCol) return value; return Math.max(value, count * itemMaxSpan); }; const clsMap = [`${antColClass}-xs-${paddingSpan(rule.xs)}`]; if (rule.sm) clsMap.push(`${antColClass}-sm-${paddingSpan(rule.sm)}`); if (rule.md) clsMap.push(`${antColClass}-md-${paddingSpan(rule.md)}`); if (rule.lg) clsMap.push(`${antColClass}-lg-${paddingSpan(rule.lg)}`); if (rule.xl) clsMap.push(`${antColClass}-xl-${paddingSpan(rule.xl)}`); if (rule.xxl) clsMap.push(`${antColClass}-xxl-${paddingSpan(rule.xxl)}`); return clsMap; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: ResponsiveService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: ResponsiveService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: ResponsiveService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [] }); const HTML_DIR = 'dir'; const RTL_DIRECTION = 'direction'; const RTL_NZ_COMPONENTS = ['modal', 'drawer', 'message', 'notification', 'image']; const RTL_YELON_COMPONENTS = ['loading', 'onboarding']; const LTR = 'ltr'; const RTL = 'rtl'; class RTLService { d = inject(Directionality); nz = inject(NzConfigService); yelon = inject(YunzaiConfigService); platform = inject(Platform); doc = inject(DOCUMENT); srv = inject(SettingsService); _dir = LTR; /** * Get or Set the current text direction * * 获取或设置当前文字方向 */ get dir() { return this._dir; } set dir(value) { this._dir = value; this.updateLibConfig(); this.updateHtml(); // Should be wait inited Promise.resolve().then(() => { this.d.valueSignal.set(value); this.d.change.emit(value); this.srv.setLayout(RTL_DIRECTION, value); }); } /** * Get the next text direction * * 获取下一次文字方向 */ get nextDir() { return this.dir === LTR ? RTL : LTR; } /** * Subscription change notification * * 订阅变更通知 */ get change() { return this.srv.notify.pipe(filter(w => w.name === RTL_DIRECTION), map(v => v.value)); } constructor() { this.dir = this.srv.layout.direction === RTL ? RTL : LTR; } /** * Toggle text direction * * 切换文字方向 */ toggle() { this.dir = this.nextDir; } updateHtml() { if (!this.platform.isBrowser) { return; } const htmlEl = this.doc.querySelector('html'); if (htmlEl) { const dir = this.dir; htmlEl.style.direction = dir; htmlEl.classList.remove(RTL, LTR); htmlEl.classList.add(dir); htmlEl.setAttribute(HTML_DIR, dir); } } updateLibConfig() { RTL_NZ_COMPONENTS.forEach(name => { this.nz.set(name, { nzDirection: this.dir }); }); RTL_YELON_COMPONENTS.forEach(name => { this.yelon.set(name, { direction: this.dir }); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: RTLService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: RTLService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: RTLService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [] }); class TitleService { destroy$ = inject(DestroyRef); _prefix = ''; _suffix = ''; _separator = ' - '; _reverse = false; tit$; DELAY_TIME = 25; doc = inject(DOCUMENT); injector = inject(Injector); title = inject(Title); menuSrv = inject(MenuService); i18nSrv = inject(YUNZAI_I18N_TOKEN); constructor() { this.i18nSrv.change.pipe(takeUntilDestroyed()).subscribe(() => this.setTitle()); } /** * Set separator * * 设置分隔符 */ set separator(value) { this._separator = value; } /** * Set prefix * * 设置前缀 */ set prefix(value) { this._prefix = value; } /** * Set suffix * * 设置后缀 */ set suffix(value) { this._suffix = value; } /** * Set whether to reverse * * 设置是否反转 */ set reverse(value) { this._reverse = value; } /** * Set the default CSS selector string * * 设置默认CSS选择器字符串 */ selector; /** * Set default title name * * 设置默认标题名 */ default = `Not Page Name`; getByElement() { return of('').pipe(delay(this.DELAY_TIME), map(() => { const el = ((this.selector != null ? this.doc.querySelector(this.selector) : null) || this.doc.querySelector('.yunzai-default__content-title h1') || this.doc.querySelector('.page-header__title')); if (el) { let text = ''; el.childNodes.forEach(val => { if (!text && val.nodeType === 3) { text = val.textContent.trim(); } }); return text || el.firstChild.textContent.trim(); } return ''; })); } getByRoute() { let next = this.injector.get(ActivatedRoute); while (next.firstChild) next = next.firstChild; const data = (next.snapshot && next.snapshot.data) || {}; if (data.titleI18n) data.title = this.i18nSrv.fanyi(data.titleI18n); return isObservable(data.title) ? data.title : of(data.title); } getByMenu() { const menus = this.menuSrv.getPathByUrl(this.injector.get(Router).url); if (!menus || menus.length <= 0) return of(''); const item = menus[menus.length - 1]; let title; if (item.i18n) title = this.i18nSrv.fanyi(item.i18n); return of(title || item.text); } /** * Set the document title */ setTitle(title) { this.tit$?.unsubscribe(); this.tit$ = of(title) .pipe(switchMap(tit => (tit ? of(tit) : this.getByRoute())), switchMap(tit => (tit ? of(tit) : this.getByMenu())), switchMap(tit => (tit ? of(tit) : this.getByElement())), map(tit => tit || this.default), map(title => (!Array.isArray(title) ? [title] : title)), takeUntilDestroyed(this.destroy$)) .subscribe(titles => { let newTitles = []; if (this._prefix) { newTitles.push(this._prefix); } newTitles.push(...titles.filter(title => !!title)); if (this._suffix) { newTitles.push(this._suffix); } if (this._reverse) { newTitles = newTitles.reverse(); } this.title.setTitle(newTitles.join(this._separator)); }); } /** * Set i18n key of the document title */ setTitleByI18n(key, params) { this.setTitle(this.i18nSrv.fanyi(key, params)); } ngOnDestroy() { this.tit$?.unsubscribe(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: TitleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: TitleService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: TitleService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [] }); class I18nPipe { i18n = inject(YUNZAI_I18N_TOKEN); transform(key, params) { return this.i18n.fanyi(key, params); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: I18nPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.1.3", ngImport: i0, type: I18nPipe, isStandalone: true, name: "i18n" }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: I18nPipe, decorators: [{ type: Pipe, args: [{ name: 'i18n' }] }] }); class YunzaiI18NGuardService { i18nSrv = inject(YUNZAI_I18N_TOKEN, { optional: true }); cogSrv = inject(YunzaiConfigService); process(route) { const lang = route.params && route.params[this.cogSrv.get('themeI18n')?.paramNameOfUrlGuard ?? 'i18n']; if (lang != null) { this.i18nSrv?.use(lang); } return of(true); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18NGuardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18NGuardService, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: YunzaiI18NGuardService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); /** * Internationalization guard, automatically recognizes the language in Url and triggers the `YUNZAI_I18N_TOKEN.use` method * * 国际化守卫,自动识别Url中的语言,并触发 `YUNZAI_I18N_TOKEN.use` 方法 * * ```ts * data: { * path: 'home', * canActivate: [ yunzaiI18nCanActivate ] * } * ``` */ const yunzaiI18nCanActivate = childRoute => inject(YunzaiI18NGuardService).process(childRoute); /** * Internationalization guard, automatically recognizes the language in Url and triggers the `YUNZAI_I18N_TOKEN.use` method * * 国际化守卫,自动识别Url中的语言,并触发 `YUNZAI_I18N_TOKEN.use` 方法 * * ```ts * data: { * path: 'home', * canActivateChild: [ yunzaiI18nCanActivateChild ] * } * ``` */ const yunzaiI18nCanActivateChild = route => inject(YunzaiI18NGuardService).process(route); var yelonElGR = { abbr: 'el-GR', exception: { 403: `Λυπούμαστε, δεν έχετε πρόσβαση σε αυτήν τη σελίδα`, 404: `Λυπούμαστε, η σελίδα αυτή δεν βρέθηκε`, 500: `Λυπούμαστε, σφάλμα διακομιστή`, backToHome: 'Επιστροφή στην αρχική σελίδα' }, noticeIcon: { emptyText: 'Δεν υπάρχουν δεδομένα', clearText: 'Καθαρισμός' }, reuseTab: { close: 'Κλείσιμο καρτέλας', closeOther: 'Κλείσιμο των άλλων καρτέλων', closeRight: 'Κλείσιμο των καρτελών δεξιά', refresh: 'Ανανέωση' }, tagSelect: { expand: 'Επέκταση', collapse: 'Σύμπτυξη' }, miniProgress: { target: 'Στόχος: ' }, st: { total: '{{range[0]}} - {{range[1]}} από {{total}}', filterConfirm: 'ΟΚ', filterReset: 'Επαναφορά' }, sf: { submit: 'Υποβολή', reset: 'Επαναφορά', search: 'Αναζήτηση', edit: 'Αποθήκευση', addText: 'Προσθήκη', removeText: 'Αφαίρεση', checkAllText: 'Επιλογή όλων', error: { 'false schema': `Η δυαδική δομή είναι ψευδής`, $ref: `Δεν είναι δυνατή η επίλυση της αναφοράς {ref}`, additionalItems: `Δεν πρέπει να έχει περισσότερα από {limit} στοιχεία`, additionalProperties: `Δεν πρέπει να έχει επιπλέον χαρακτηριστικά`, anyOf: `Πρέπει να ταιριάζει με κάποια απο τις δομές στο "anyOf"`, dependencies: `τα χαρακτηριστικά {deps} είναι απαραίτητα, όταν υπάρχει το χαρακτηριστικό {property}`, enum: `Πρέπει να είναι ίσο με μία από τις προκαθορισμένες τιμές`, format: `Πρέπει να έχει την μορφή "{format}"`, type: `Πρέπει να είναι {type}`, required: `Απαιτείται`, maxLength: `Δεν πρέπει να είναι μεγαλύτερο από {limit} χαρακτήρες`, minLength: `Δεν πρέπει να είναι μικρότερο από {limit} χαρακτήρες`, minimum: `Πρέπει να είναι {comparison} {limit}`, formatMinimum: `Πρέπει να είναι {comparison} {limit}`, maximum: `Πρέπει να είναι {comparison} {limit}`, formatMaximum: `Πρέπει να είναι {comparison} {limit}`, maxItems: `Δεν πρέπει να έχει περισσότερα από {limit} στοιχεία`, minItems: `Δεν πρέπει να έχει λιγότερα από {limit} στοιχεία`, maxProperties: `Δεν πρέπει να έχει περισσότερα από {limit} χαρακτηριστικά`, minProperties: `Δεν πρέπει να έχει λιγότερα από {limit} χαρακτηριστικά`, multipleOf: `Πρέπει να είναι πολλαπλάσιο του {multipleOf}`, not: `Δεν πρέπει να είναι εγκύρο, σύμφωνα με την δομή στο "not"`, oneOf: `Πρέπει να ταιριάζει με ακριβώς μια απο τις δομές στο "oneOf"`, pattern: `Πρέπει να ταιριάζει με το πρότυπο "{pattern}"`, uniqueItems: `Τα στοιχεία δεν πρέπει να επαναλαμβάνονται (τα στοιχεία ## {j} και {i} είναι ίδια)`, custom: `Πρέπει να έχει την μορφή`, propertyNames: `Το όνομα του χαρακτηριστικού "{propertyName}" δεν είναι έγκυρο`, patternRequired: `Πρέπει να υπάρχει το χαρακτηριστικό αντιπαραβολής προτύπου "{missingPattern}"`, switch: `Πρέπει να περάσει ο έλεγχος εγκυρότητας της λέξης-κλειδιού με την χρήση της "switch", η περίπτωση {caseIndex} αποτυγχάνει`, const: `Πρέπει να είναι ίσο με σταθερά`, contains: `Πρέπει να περιέχει κάποιο έγκυρο στοιχείο`, formatExclusiveMaximum: `formatExclusiveMaximum πρέπει να είναι boolean`, formatExclusiveMinimum: `formatExclusiveMinimum πρέπει να είναι boolean`, if: `Πρέπει να ταιριάζει στην δομή "{failingKeyword}"` } }, onboarding: { skip: `Παράλειψη`, prev: `Προηγούμενο`, next: `Επόμενο`, done: `Ολοκληρώθηκε` } }; var yelonEnUS = { abbr: 'en-US', exception: { 403: `Sorry, you don't have access to this page`, 404: `Sorry, the page you visited does not exist`, 500: `Sorry, the server is reporting an error`, backToHome: 'Back To Home' }, noticeIcon: { emptyText: 'No data', clearText: 'Clear' }, reuseTab: { close: 'Close tab', closeOther: 'Close other tabs', closeRight: 'Close tabs to right', refresh: 'Refresh' }, tagSelect: { expand: 'Expand', collapse: 'Collapse' }, miniProgress: { target: 'Target: ' }, st: { total: '{{range[0]}} - {{range[1]}} of {{total}}', filterConfirm: 'OK', filterReset: 'Reset' }, sf: { submit: 'Submit', reset: 'Reset', search: 'Search', edit: 'Save', addText: 'Add', removeText: 'Remove', checkAllText: 'Check all', error: { 'false schema': `Boolean schema is false`, $ref: `Can't resolve reference {ref}`, additionalItems: `Should not have more than {limit} item`, additionalProperties: `Should not have additional properties`, anyOf: `Should match some schema in "anyOf"`, dependencies: `should have property {deps} when property {property} is present`, enum: `Should be equal to one of predefined values`, format: `Should match format "{format}"`, type: `Should be {type}`, required: `Required`, maxLength: `Should not be longer than {limit} character`, minLength: `Should not be shorter than {limit} character`, minimum: `Should be {comparison} {limit}`, formatMinimum: `Should be {comparison} {limit}`, maximum: `Should be {comparison} {limit}`, formatMaximum: `Should be {comparison} {limit}`, maxItems: `Should not have more than {l