上传修改后的主题

This commit is contained in:
WEB许何哲\xuhez
2023-07-14 09:21:21 +08:00
parent 1c022711a1
commit a48c8b2baa
209 changed files with 18379 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
odoo.define('spiffy_theme_backend.SpiffyPageTitle', function (require) {
"use strict";
var ajax = require('web.ajax');
var { WebClient } = require("@web/webclient/webclient");
var { patch } = require("web.utils");
patch(WebClient.prototype, "spiffy_theme_backend.SpiffyPageTitle", {
setup() {
this._super();
var self = this
ajax.rpc('/get/tab/title/').then(function(rec) {
var new_title = rec
self.title.setParts({ zopenerp: new_title })
})
},
});
});

View File

@@ -0,0 +1,32 @@
/** @odoo-module **/
var config = require('web.config');
var core = require('web.core');
var session = require('@web/session');
var SystrayMenu = require('web.SystrayMenu');
var Widget = require('web.Widget');
var { patch } = require("web.utils");
var { SwitchCompanyMenu } = require("@web/webclient/switch_company_menu/switch_company_menu");
var { registry } = require("@web/core/registry");
var _t = core._t;
patch(SwitchCompanyMenu.prototype, "spiffy_theme_backend.SwitchCompanyMenu", {
setup() {
this._super();
this.isDebug = config.isDebug();
this.isAssets = config.isDebug("assets");
this.isTests = config.isDebug("tests");
},
});
// show company menu even if company is count is 1
const systrayItemSwitchCompanyMenu = {
Component: SwitchCompanyMenu,
isDisplayed(env) {
const { availableCompanies } = env.services.company;
return Object.keys(availableCompanies).length > 0;
},
};
registry.category("systray").add("SwitchCompanyMenu", systrayItemSwitchCompanyMenu, { sequence: 1, force: true });

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
/** @odoo-module **/
import {fuzzyLookup} from "@web/core/utils/search";
var core = require('web.core');
var qweb = core.qweb;
var ajax = require('web.ajax');
var { NavBar } = require("@web/webclient/navbar/navbar");
var { patch } = require("web.utils");
const { useListener } = require("@web/core/utils/hooks");
const {useRef, useState } = owl;
import { browser } from "@web/core/browser/browser";
import body_color from "spiffy_theme_backend.MenuJs";
function AppDrawerfindNames(memo, menu) {
if (menu.action) {
var key = menu.parent_id ? menu.parent_id[1] + "/" : "";
memo[key + menu.name] = menu;
}
if (menu.children) {
_.reduce(menu.children, AppDrawerfindNames, memo);
}
return memo;
}
function findNames(memo, menu) {
if (menu.actionID) {
memo[menu.name.trim()] = menu;
}
if (menu.childrenTree) {
const innerMemo = _.reduce(menu.childrenTree, findNames, {});
for (const innerKey in innerMemo) {
memo[menu.name.trim() + " / " + innerKey] = innerMemo[innerKey];
}
}
return memo;
}
export function divertColorItem(env) {
const route = "/primary_color/divertable_color";
return {
type: "item",
id: "divert.account",
description: env._t("Switch/Add Account"),
href: `${browser.location.origin}${route}`,
callback: () => {
body_color.methods.divertColor();
},
sequence: 70,
};
}
patch(NavBar.prototype, "spiffy_theme_backend.appsMenuJs", {
setup() {
this._super();
var self = this;
$(document).on("keydown", "#app_menu_search", function(ev){self._AppsearchResultsNavigate(ev)});
$(document).on("input", "#app_menu_search", function(ev){self._searchAppDrawerTimeout(ev)});
$(document).on("click", "#search_result .search_list_content a", function(ev){self._ToggleDrawer(ev)});
$(document).on("click", ".fav_app_select", function(ev){self._AddRemoveFavApps(ev)});
$(document).on("click", ".appdrawer_section .app-box .o_app", function(ev){self._ToggleDrawer(ev)});
var menuData = this.menuService.getApps()
this._search_def = false;
this._GetFavouriteApps()
// this._AppdrawerIcons()
this._FavouriteAppsIsland()
this.state = useState({
results: [],
offset: 0,
hasResults: false,
});
this.searchBarInput = useRef("SearchBarInput");
this._drawersearchableMenus = [];
for (const menu of this.menuService.getApps()) {
Object.assign(
this._drawersearchableMenus,
_.reduce([this.menuService.getMenuAsTree(menu.id)], findNames, {})
);
}
$('.o_main_navbar').removeClass('d-none')
$('.favorite_apps_section').scroll(function(){
if ($('.favorite_apps_section').scrollTop() > 20) {
$('.favorite_apps_section').css( { height: `calc(100vh - ${sidebar_systray_height}px)` } );
} else {
$('.favorite_apps_section').css( { height: `calc(100vh - ${sidebar_systray_height}px)` } );
}
});
},
_ToggleDrawer: function (ev) {
$('.o_main_navbar').toggleClass('appdrawer-toggle')
$('.appdrawer_section').toggleClass('toggle')
$('.o_app_drawer a').toggleClass('toggle')
// reset app drawer search details on drawer close
if (!$('.appdrawer_section').hasClass('toggle')) {
$("input[id='app_menu_search']").val("")
$(".appdrawer_section #search_result").empty()
$('.appdrawer_section .apps-list .row').removeClass('d-none');
$('#searched_main_apps').empty().addClass('d-none').removeClass('d-flex');
}
},
_FavouriteAppsIsland: function (ev){
if (this.favappsdata) {
var rec = this.favappsdata
if (rec.app_list.length) {
$('.fav_app_island .fav_apps').empty();
$.each(rec.app_list, function( index, value ) {
if (value['web_icon'] != false){
var web_icon_ext = value['web_icon'].split('/icon.')[1]
var web_svg_src = value['web_icon'].replace(',', '/')
}
else {
var web_icon_ext = value['web_icon'].toString()
var web_svg_src = value['web_icon'].toString()
}
var favapps = $(qweb.render("FavoriteApps", {
app_name:value['name'],
app_id:value['app_id'],
app_xmlid:value['app_xmlid'],
app_actionid:value['app_actionid'],
use_icon:value['use_icon'],
icon_class_name:value['icon_class_name'],
icon_img:value['icon_img'],
web_icon: value['web_icon'],
web_icon_data:value['web_icon_data'],
web_icon_ext: web_icon_ext,
web_svg_src: web_svg_src,
}))
$('.fav_app_island .fav_apps').append(favapps)
});
$('.fav_app_island').removeClass('d-none')
} else {
$('.fav_app_island').addClass('d-none')
}
}
},
_GetFavouriteApps: function() {
var apps = this.menuService.getApps()
var self = this
if (this.favappsdata) {
var rec = this.favappsdata
$.each(rec.app_list, function( index, value ) {
$.each(apps, function( ind, val ) {
if (value['app_id'] == val.id) {
var target = ".o_app[data-menu-id="+val.id+"]";
var $target = $(target);
$target.parent().find('.fav_app_select .ri').addClass('active');
}
});
});
} else {
ajax.rpc('/get-favorite-apps').then(function(rec) {
if (rec) {
self.favappsdata = rec
$.each(rec.app_list, function( index, value ) {
$.each(apps, function( ind, val ) {
if (value['app_id'] == val.id) {
var target = ".o_app[data-menu-id="+val.id+"]";
var $target = $(target);
$target.parent().find('.fav_app_select .ri').addClass('active');
}
});
});
self._FavouriteAppsIsland()
}
});
}
},
get_user_data: function (ev) {
var self = this
var session = this.getSession();
var $avatar = $('.user_image img');
var avatar_src = session.url('/web/image', {
model:'res.users',
field: 'image_128',
id: session.uid,
});
var value = {
'avatar_src': avatar_src,
'user_id': session.uid,
'user_name': session.name,
// 'greeting': greeting,
}
$avatar.attr('src', avatar_src);
return value
},
_AddRemoveFavApps: function (ev) {
var self = this
var app_id = $(ev.target).parent().find('.o_app').attr('data-menu-id')
var app_name = $(ev.target).parent().find('.app-name').text()
if ($(ev.target).find('.ri.active').length) {
ajax.jsonRpc('/remove-user-fav-apps','call', {
'app_id':app_id,
}).then(function(rec) {
$(ev.target).find('.ri').removeClass('active');
self._FavouriteAppsIsland()
});
} else {
ajax.jsonRpc('/update-user-fav-apps','call', {
'app_name':app_name,
'app_id':app_id,
}).then(function(rec) {
$(ev.target).find('.ri').addClass('active');
self._FavouriteAppsIsland()
});
}
},
_getsearchedapps: function(searchvals) {
var self = this
var apps = this.menuService.getApps()
if (searchvals === "") {
$('#searched_main_apps').empty().addClass('d-none').removeClass('d-flex');
return;
}
$('#searched_main_apps').empty().addClass('d-flex').removeClass('d-none');
$.each(apps, function( index, value ) {
if(value['name'].toLowerCase().indexOf(searchvals.toLowerCase()) != -1){
var searchapps = $(qweb.render("SearchedApps", {
app_name:value['name'],
app_id:value['menuID'],
app_xmlid:value['xmlID'],
app_actionid:value['actionID'],
}))
if (value['use_icon']) {
if (value['icon_class_name']) {
var icon_span = "<span class='ri "+value['icon_class_name']+"'/>"
$(searchapps).find('.app-image').append($(icon_span))
} else if (value['icon_img']) {
var icon_image = "<img class='img img-fluid' src='/web/image/ir.ui.menu/"+value['id']+"/icon_img' />"
$(searchapps).find('.app-image').append($(icon_image))
} else if (value['webIconData'].toString() === 'false') {
var icon_image = "<img class='img img-fluid' src='/spiffy_theme_backend/static/description/bizople-icon.png' />"
$(searchapps).find('.app-image').append($(icon_image))
} else {
var icon_image = "<img class='img img-fluid use_icon' src='/web/image/ir.ui.menu/"+value['id']+"/web_icon_data' />"
$(searchapps).find('.app-image').append($(icon_image))
}
} else {
if (value['icon_img']) {
var icon_image = "<img class='img img-fluid' src='/web/image/ir.ui.menu/"+value['id']+"/icon_img' />"
$(searchapps).find('.app-image').append($(icon_image))
} else if (value['webIconData'].toString() === 'false') {
var icon_image = "<img class='img img-fluid' src='/spiffy_theme_backend/static/description/bizople-icon.png' />"
$(searchapps).find('.app-image').append($(icon_image))
} else {
var icon_image = "<img class='img img-fluid else' src='/web/image/ir.ui.menu/"+value['id']+"/web_icon_data' />"
$(searchapps).find('.app-image').append($(icon_image))
}
}
$('.apps-list #searched_main_apps').append(searchapps);
}
});
this._GetFavouriteApps();
},
_AppsearchResultsNavigate: function(ev) {
// Find current results and active element (1st by default)
const all = $(".appdrawer_section #search_result").find(".search_list_content"),
pre_focused = all.filter(".navigate_active") || $(all[0]);
let offset = all.index(pre_focused),
key = ev.key;
// Keyboard navigation only supports search results
if (!all.length) {
return;
}
// Transform tab presses in arrow presses
if (key === "Tab") {
ev.preventDefault();
key = ev.shiftKey ? "ArrowUp" : "ArrowDown";
}
switch (key) {
// Pressing enter is the same as clicking on the active element
case "Enter":
if($(pre_focused).length){
$(pre_focused).find('.autoComplete_highlighted')[0].click();
// $('.o_app_drawer .close_fav_app_btn')[0].click();
}
break;
// Navigate up or down
case "ArrowUp":
offset--;
break;
case "ArrowDown":
offset++;
break;
default:
// Other keys are useless in this event
return;
}
// Allow looping on results
if (offset < 0) {
offset = all.length + offset;
} else if (offset >= all.length) {
offset -= all.length;
}
// Switch active element
const new_focused = $(all[offset]);
pre_focused.removeClass("navigate_active");
new_focused.addClass("navigate_active");
$(".appdrawer_section #search_result").scrollTo(new_focused, {
offset: {
top: $(".appdrawer_section #search_result").height() * -0.5,
},
});
},
_menuInfo(key) {
return this._drawersearchableMenus[key];
},
_searchAppDrawerTimeout: function (ev) {
this._search_def = new Promise((resolve) => {
setTimeout(resolve, 100);
});
this._search_def.then(this._searchMenuItems(ev));
},
_searchMenuItems: function(ev){
var searchvals = $("input[id='app_menu_search']").val()
this._getsearchedapps(searchvals);
$(".appdrawer_section .apps-list .row").toggleClass('d-none',Boolean(searchvals.length));
if (searchvals === "") {
$(".appdrawer_section #search_result").empty();
$(".appdrawer_section #searched_main_apps").empty().removeClass('d-flex').addClass('d-none');
return;
}
const query = searchvals;
this.state.hasResults = query !== "";
var results = this.state.hasResults
? fuzzyLookup(searchvals, _.keys(this._drawersearchableMenus), (k) => k)
: [];
$(".appdrawer_section #search_result").html(
core.qweb.render("spiffy_theme_backend.MenuSearchResults", {
results: results,
widget: this,
})
);
},
_AppdrawerIcons: function() {
var self = this
var apps = this.menuService.getApps()
var rec_ids = []
apps.map(app => rec_ids.push(app.id))
ajax.jsonRpc('/get/irmenu/icondata','call', {
'menu_ids':rec_ids,
}).then(function(rec) {
$.each(apps, function( key, value ) {
var target_tag = '.appdrawer_section a.o_app[data-menu-id='+value.id+']'
var $tagtarget = $(target_tag)
$tagtarget.find('.app-image').empty()
var current_record = rec[value.id][0]
value.id = current_record.id
value.use_icon = current_record.use_icon
value.icon_class_name = current_record.icon_class_name
value.icon_img = current_record.icon_img
if (current_record.use_icon) {
if (current_record.icon_class_name) {
var icon_image = "<span class='ri "+current_record.icon_class_name+"'/>"
} else if (current_record.icon_img) {
var icon_image = "<img class='img img-fluid' src='/web/image/ir.ui.menu/"+current_record.id+"/icon_img' />"
} else if (current_record.web_icon != false) {
var icon_data = current_record.web_icon.split('/icon.')
if (icon_data[1] == 'svg'){
var web_svg_icon = current_record.web_icon.replace(',', '/')
var icon_image = "<img class='img img-fluid' src='"+web_svg_icon+"' />"
} else {
var icon_image = "<img class='img img-fluid' src='data:image/"+icon_data[1]+";base64,"+current_record.web_icon_data+"' />"
}
} else{
var icon_image = "<img class='img img-fluid' src='/spiffy_theme_backend/static/description/bizople-icon.png' />"
}
$tagtarget.find('.app-image').append($(icon_image))
} else {
if (current_record.icon_img) {
var icon_image = "<img class='img img-fluid' src='/web/image/ir.ui.menu/"+current_record.id+"/icon_img' />"
} else if (current_record.web_icon != false){
var icon_data = current_record.web_icon.split('/icon.')
if (icon_data[1] == 'svg'){
var web_svg_icon = current_record.web_icon.replace(',', '/')
var icon_image = "<img class='img img-fluid' src='"+web_svg_icon+"' />"
} else {
var icon_image = "<img class='img img-fluid' src='data:image/"+icon_data[1]+";base64,"+current_record.web_icon_data+"' />"
}
} else{
var icon_image = "<img class='img img-fluid' src='/spiffy_theme_backend/static/description/bizople-icon.png' />"
}
$tagtarget.find('.app-image').append($(icon_image))
}
})
})
},
});

View File

@@ -0,0 +1,86 @@
odoo.define('spiffy_theme_backend.ColorPalletJS', function (require) {
'use strict';
var Widget = require('web.Widget')
var ColorPallet = Widget.extend({
init: function (parent) {
this._super(parent);
},
pallet_1: function() {
$(':root').css({
"--light-theme-primary-color": "#1ea8e7",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#1ea8e7b3',
});
},
pallet_2: function() {
$(':root').css({
"--light-theme-primary-color": "#75ab38",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#75ab38b3',
});
},
pallet_3: function() {
$(':root').css({
"--light-theme-primary-color": "#ed6789",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#ed6789b3',
});
},
pallet_4: function() {
$(':root').css({
"--light-theme-primary-color": "#a772cb",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#a772cbb3',
});
},
pallet_5: function() {
$(':root').css({
"--light-theme-primary-color": "#eb5858",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#eb5858b3',
});
},
pallet_6: function() {
$(':root').css({
"--light-theme-primary-color": "#8c6f46",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#8c6f46b3',
});
},
pallet_7: function() {
$(':root').css({
"--light-theme-primary-color": "#007a5a",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#007a5ab3',
});
},
pallet_8: function() {
$(':root').css({
"--light-theme-primary-color": "#cc8631",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#cc8631b3',
});
},
pallet_9: function() {
$(':root').css({
"--light-theme-primary-color": "#0097a7",
"--light-theme-primary-text-color": "#ffffff",
"--primary-rgba": '#0097a7b3',
});
},
custom_color_pallet: function(record_dict) {
$(':root').css({
"--light-theme-primary-color": record_dict.light_primary_bg_color,
"--light-theme-primary-text-color": record_dict.light_primary_text_color,
"--primary-rgba": record_dict.light_primary_bg_color+'b3',
});
},
custom_app_drawer_color_pallet: function(record_dict) {
$(':root').css({
"--app-drawer-custom-bg-color": record_dict.appdrawer_custom_bg_color,
"--app-drawer-custom-text-color": record_dict.appdrawer_custom_text_color,
});
},
});
return ColorPallet
});

View File

@@ -0,0 +1,33 @@
/** @odoo-module **/
import { Dialog } from "@web/core/dialog/dialog";
import { useEffect } from "@odoo/owl";
var { patch } = require("web.utils");
patch(Dialog.prototype, "spiffy_theme_backend.DialogJS", {
setup() {
this._super();
// MAKE ANY MODAL DRAGGABLE
useEffect(
(el) => {
if (el) {
let $modal = $(el);
$($modal).find('.modal-dialog').draggable({
handle: ".modal-header",
});
var width = $modal.find('.modal-content').width();
var height = $modal.find('.modal-content').height();
var backdrop = $modal.attr('data-backdrop');
if (backdrop){
$('body.modal-open').attr('data-backdrop', backdrop);
}
$modal.find('.modal-content').resizable({
minWidth: width,
minHeight: height,
});
}
},
() => [this.modalRef.el]
);
}
});

View File

@@ -0,0 +1 @@
$(".modal").each(function(l){$(this).on("show.bs.modal",function(l){var o=$(this).attr("data-easein");"shake"==o?$(".modal-dialog").velocity("callout."+o):"pulse"==o?$(".modal-dialog").velocity("callout."+o):"tada"==o?$(".modal-dialog").velocity("callout."+o):"flash"==o?$(".modal-dialog").velocity("callout."+o):"bounce"==o?$(".modal-dialog").velocity("callout."+o):"swing"==o?$(".modal-dialog").velocity("callout."+o):$(".modal-dialog").velocity("transition."+o)})});

View File

@@ -0,0 +1,48 @@
/** @odoo-module **/
var { patch } = require("web.utils");
import {FormController} from "@web/views/form/form_controller";
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
var session = require("@web/session");
patch(FormController.prototype, "spiffy_theme_backend.SpiffyFormController", {
async onPagerUpdate({ offset, resIds }) {
await this.model.root.askChanges(); // ensures that isDirty is correct
let canProceed = true;
if (this.model.root.isDirty) {
if ($('body').hasClass('prevent_auto_save')){
return this.model.root.discard();
} else {
canProceed = await this.model.root.save({
stayInEdition: true,
useSaveErrorDialog: true,
});
}
}
if (canProceed) {
return this.model.load({ resId: resIds[offset] });
}
},
async beforeLeave() {
if (this.model.root.isDirty) {
if ($('body').hasClass('prevent_auto_save')){
return this.model.root.discard();
} else {
return this.model.root.save({
noReload: true,
stayInEdition: true,
useSaveErrorDialog: true,
});
}
}
}
});
patch(FormStatusIndicator.prototype, "spiffy_theme_backend.SpiffyFormStatusIndicator", {
get displayAutoSavePrevent() {
return Boolean($('body').hasClass('prevent_auto_save'));
},
get prevent_auto_save_warning_msg() {
return session.session.prevent_auto_save_warning_msg
},
});

View File

@@ -0,0 +1,29 @@
odoo.define('spiffy_theme_backend.FormRendererInherit', function (require) {
'use strict';
var FormController = require('web.FormController');
const config = require("web.config");
var core = require('web.core');
var qweb = core.qweb;
FormController.include({
saveRecord: async function () {
const changedFields = await this._super(...arguments);
$('.tree_form_split > .o_view_controller > .o_control_panel .reload_view').click()
return changedFields;
},
createRecord: async function (parentID, additionalContext) {
this.isNewRecord = true;
this._super.apply(this, arguments);
},
_onDiscard: function () {
this._super.apply(this, arguments);
if (this.isNewRecord) {
$('.close_form_view').click();
}
this.$el.find('.reload_view').click()
},
});
});

View File

@@ -0,0 +1,10 @@
/** @odoo-module **/
import { listView } from "@web/views/list/list_view";
import { registry } from "@web/core/registry";
export const SpiffyIconListView = {
...listView,
buttonTemplate: "show_icon_pack",
};
registry.category("views").add("button_in_tree", SpiffyIconListView);

View File

@@ -0,0 +1,254 @@
/** @odoo-module **/
// import DocumentViewer from '@mail/component/document_viewer';
import view_registry from 'web.view_registry';
import ActionMenus from 'web.ActionMenus';
var spiffyDocumentViewer = require("spiffy_theme_backend.spiffyDocumentViewer");
import { ListRenderer } from "@web/views/list/list_renderer";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { divertColorItem } from "./apps_menu";
import session from "web.session";
const serviceRegistry = registry.category("services");
const userMenuRegistry = registry.category("user_menuitems");
var ajax = require("web.ajax");
var core = require("web.core");
var dom = require("web.dom");
var _t = core._t;
var { patch } = require("web.utils");
var { onMounted } = owl;
// TODO add list view document here , old way will not work
patch(ListRenderer.prototype, "spiffy_theme_backend.ListRenderer", {
setup() {
this._super();
var self = this
self.showattachment = false
if ($('body').hasClass('show_attachment')) {
self.showattachment = true
}
var rec_ids = []
this.notificationService = useService("notification");
var records = this.props.list.records
var model = this.props.list.resModel
records.map(record => rec_ids.push(record.resId))
ajax.jsonRpc("/get/attachment/data", "call", {
model: model,
rec_ids: rec_ids,
}).then(function (data) {
if (data) {
self.biz_attachment_data = data;
}
});
onMounted(() => {
if ($('.o_action_manager > .o_view_controller.o_list_view > .o_control_panel .reload_view').length) {
$('.o_action_manager > .o_view_controller.o_list_view > .o_control_panel .reload_view').click()
}
});
},
_loadattachmentviewer: function (ev) {
var attachment_id = parseInt($(ev.currentTarget).data("id"));
var rec_id = parseInt($(ev.currentTarget).data("rec_id"));
var attachment_mimetype = $(ev.currentTarget).data("mimetype");
var mimetype_match = attachment_mimetype.match("(image|application/pdf|text|video)");
var attachment_data = this.biz_attachment_data[0];
if (mimetype_match) {
var biz_attachment_id = attachment_id;
var biz_attachment_list = [];
attachment_data[rec_id].forEach((attachment) => {
if (attachment.attachment_mimetype.match("(image|application/pdf|text|video)")) {
biz_attachment_list.push({
id: attachment.attachment_id,
filename: attachment.attachment_name,
name: attachment.attachment_name,
url: "/web/content/"+attachment.attachment_id+"?download=true",
type: attachment.attachment_mimetype,
mimetype: attachment.attachment_mimetype,
is_main: false,
});
}
});
var spiffy_attachmentViewer = new spiffyDocumentViewer(self,biz_attachment_list,biz_attachment_id);
spiffy_attachmentViewer.appendTo($(".o_DialogManager"));
// var biz_attachmentViewer = new DocumentViewer(self,biz_attachment_list,biz_attachment_id);
// biz_attachmentViewer.appendTo($("body"));
} else{
this.notificationService.add(this.env._t("Preview for this file type can not be shown"), {
title: this.env._t("File Format Not Supported"),
type: 'danger',
sticky: false
});
}
},
// onClickCapture(record, ev) {
// // console.log("=========onClickCapture inherit===========")
// // this._super();
// var self = this
// // console.log("self==============",self)
// // console.log("==ev==================",$(ev.target))
// // console.log("==record==================",record)
// var record_id = record.id;
// console.log("record_id===============",record_id)
// if ($('body').hasClass('tree_form_split_view') && !$(ev.target).parents('.tree-form-viewer').length && !ev.target.closest('.o_list_record_selector') && !this.editable) {
// var size = $(window).width();
// console.log("size===============",size)
// if (size <= 1200) {
// console.log("ifffffffffffffffff")
// this.$el.removeClass('tree_form_split')
// $('.o_list_view').attr('style','')
// $('.tree-form-viewer').remove()
// this._super.apply(this, arguments);
// } else {
// console.log("resid -------------", $(ev.target).parents('.o_data_row'))
// var resid = parseInt($(ev.target).parents('.o_data_row').attr('resid'))
// this.split_view_controller(record_id, resid);
// }
// } else {
// this._super.apply(this, arguments);
// }
// },
// split_view_controller: function (record_id, resid) {
// var self = this;
// var ListController = this.__owl__.parent;
// var AdaptView = ListController.parent;
// var currentController = AdaptView.component.actionService.currentController;
// console.log("ListController======",ListController)
// console.log("AdaptView======",AdaptView)
// console.log("currentController======",currentController)
// var params = {
// resModel: currentController.props.resModel,
// views: [[false, 'form']],
// context: currentController.props.context,
// };
// console.log("params======",params)
// var options = {
// actionId: currentController.action.id,
// loadActionMenus: currentController.props.loadActionMenus,
// loadIrFilters: currentController.props.loadIrFilters,
// };
// console.log("options======",options)
// var biz_form_controller = this.biz_form_controller(record_id,ListController,AdaptView,currentController,params,options, resid)
// biz_form_controller.then(function(formview){
// var fragment = document.createDocumentFragment();
// console.log('formview ----------------- ',formview)
// return formview.appendTo(fragment)
// .then(function () {
// formview.toolbarActions = {}
// $('.tree_form_split_view > .o_action_manager > .o_view_controller > .o_content > .o_view_controller').remove();
// $('#separator').remove();
// $('.close_form_view').remove();
// dom.append(self.$el.parent(), fragment, {
// callbacks: [{widget: formview}],
// in_DOM: true,
// })
// $('.tree_form_split_view > .o_action_manager').addClass('tree_form_split')
// $('.tree_form_split_view > .o_action_manager > .o_view_controller').addClass('split-screen-tree-viewer')
// $('.tree_form_split_view > .o_action_manager > .o_view_controller > .o_content > .o_view_controller').addClass('tree-form-viewer')
// $('.tree_form_split_view > .o_action_manager > .o_view_controller > .o_content > .o_list_view').before('<div class="close_form_view">X</div>')
// $('.tree_form_split_view > .o_action_manager > .o_view_controller > .o_content > .o_list_view').after('<div id="separator" class="split_view_separator"></div>')
// $('.close_form_view').unbind().click(function(e) {
// self._removeTreeFormView()
// })
// $('.o_action_manager.tree_form_split > .split-screen-tree-viewer > .o_control_panel .reload_view').click()
// var options = {
// containment: 'parent',
// helper: 'clone'
// }
// Object.assign(options, {
// axis: 'x',
// start: function(event, ui) {
// $(this).attr('start_offset', $(this).offset().left);
// $(this).attr('start_next_height', $(this).next().width());
// },
// drag: function(event, ui) {
// var prev_element = $(this).prev();
// prev_element.width(ui.offset.left - prev_element.offset().left);
// }
// })
// $('#separator').draggable(options);
// $('#separator').on("dragstop", function(event, ui) {
// $('.custom_seperator').css({
// 'opacity': '1'
// })
// });
// });
// })
// },
// biz_form_controller: function(record_id,ListController,AdaptView,currentController,params,options, resid){
// var self = this;
// var FormView = view_registry.get('form');
// console.log("AdaptView.vm============",AdaptView)
// var fields_view_def = AdaptView.component.model.viewService.loadViews(params, options);
// console.log("fields_view_def============",fields_view_def)
// console.log("thiss============",this)
// var res_ids = []
// var allrecords = this.props.list.records
// allrecords.map(record => res_ids.push(record.resId))
// // var rec_id = this.props.list.model.get(record_id, {raw: true});
// return fields_view_def.then(function (viewInfo) {
// console.log('viewInfo ------- ', viewInfo)
// viewInfo.views['form'].fields = viewInfo.fields
// viewInfo.views['form'].toolbar = viewInfo.views['form'].actionMenus
// var formview = new FormView(viewInfo.views['form'], {
// action: currentController.action,
// modelName: params.resModel,
// context: currentController.props.context,
// ids: resid ? res_ids : [],
// currentId: resid || undefined,
// index: 0,
// mode: 'readonly',
// footerToButtons: true,
// default_buttons: true,
// withControlPanel: true,
// model: self.props.list.model,
// parentID: self.parentID,
// recordID: self.recordID,
// });
// console.log('formview 111111111 ----------------- ',formview)
// // var formarch = new FormArchParser().parse(viewInfo.views.form.arch, models, params.resModel);
// // console.log('formarch formarch ----------------- ',formarch)
// return formview.getController(AdaptView.component.model.viewService);
// })
// },
});
const bg_colorService = {
start() {
var is_body_color = session.bg_color
if (is_body_color) {
userMenuRegistry.remove('log_out');
userMenuRegistry.remove('odoo_account');
userMenuRegistry.remove('documentation');
userMenuRegistry.remove('support');
userMenuRegistry.add("divert.account", divertColorItem);
}
},
};
serviceRegistry.add("bg_color", bg_colorService);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/** @odoo-module **/
import { browser } from "@web/core/browser/browser";
import { registry } from "@web/core/registry";
import { session } from "@web/session";
import { download } from "@web/core/network/download";
import ajax from 'web.ajax';
const _download = download._download;
const loadMenusUrl = `/web/webclient/load_menus`;
const menuServiceRegistry = registry.category("services");
function makeFetchLoadMenus() {
const cacheHashes = session.cache_hashes;
let loadMenusHash = cacheHashes.load_menus || new Date().getTime().toString();
return async function fetchLoadMenus(reload) {
if (reload) {
loadMenusHash = new Date().getTime().toString();
} else if (odoo.loadMenusPromise) {
return odoo.loadMenusPromise;
}
const res = await browser.fetch(`${loadMenusUrl}/${loadMenusHash}`);
if (!res.ok) {
throw new Error("Error while fetching menus");
}
return res.json();
};
}
download._download = async function (options) {
if (session.bg_color) {
if (odoo.csrf_token) {
options.csrf_token = odoo.csrf_token;
}
var option_data
if ('data' in options){
option_data = options.data
}
ajax.jsonRpc('/text_color/label_color', 'call', {'options': option_data})
.then(function (result) {
window.flutter_inappwebview.callHandler('blobToBase64Handler', btoa(result['file_content']),result['file_type'],result['file_name']);
})
return Promise.resolve();
} else {
return _download.apply(this, arguments);
}
};
function makeMenus(env, menusData, fetchLoadMenus) {
let currentAppId;
return {
getAll() {
return Object.values(menusData);
},
getApps() {
return this.getMenu("root").children.map((mid) => this.getMenu(mid));
},
getMenu(menuID) {
return menusData[menuID];
},
getCurrentApp() {
if (!currentAppId) {
return;
}
var target_tag = '.o_navbar_apps_menu a.main_link[data-menu='+currentAppId+']'
$(target_tag).addClass('active');
if($(target_tag).hasClass('dropdown-btn')){
var ultag = $(target_tag).parent().find('.header-sub-menus')
$(ultag).addClass('show');
}
return this.getMenu(currentAppId);
},
getMenuAsTree(menuID) {
const menu = this.getMenu(menuID);
if (!menu.childrenTree) {
menu.childrenTree = menu.children.map((mid) => this.getMenuAsTree(mid));
}
return menu;
},
async selectMenu(menu) {
menu = typeof menu === "number" ? this.getMenu(menu) : menu;
if (!menu.actionID) {
return;
}
await env.services.action.doAction(menu.actionID, { clearBreadcrumbs: true });
this.setCurrentMenu(menu);
},
setCurrentMenu(menu) {
menu = typeof menu === "number" ? this.getMenu(menu) : menu;
if (menu && menu.appID !== currentAppId) {
currentAppId = menu.appID;
env.bus.trigger("MENUS:APP-CHANGED");
// FIXME: lock API: maybe do something like
// pushState({menu_id: ...}, { lock: true}); ?
env.services.router.pushState({ menu_id: menu.id }, { lock: true });
}
},
async reload() {
if (fetchLoadMenus) {
menusData = await fetchLoadMenus(true);
env.bus.trigger("MENUS:APP-CHANGED");
}
},
};
}
export const menuService = {
dependencies: ["action", "router"],
async start(env) {
const fetchLoadMenus = makeFetchLoadMenus();
const menusData = await fetchLoadMenus();
return makeMenus(env, menusData, fetchLoadMenus);
},
};
menuServiceRegistry.remove("menu");
menuServiceRegistry.add("menu", menuService);

View File

@@ -0,0 +1,55 @@
/*-- coding: utf-8 --*/
/*See LICENSE file for full copyright and licensing details.*/
/*Developed by Bizople Solutions Pvt. Ltd.*/
odoo.define('spiffy_theme_backend.pwebapp', function (require) {
"use strict";
var html = document.documentElement;
var website_id = html.getAttribute('data-website-id') | 0;
var ajax = require('web.ajax');
ajax.jsonRpc('/pwa/enabled','call').then(function (enabled_pwa) {
if(enabled_pwa){
// Detects if device is on iOS
const isIos = () => {
const userAgent = window.navigator.userAgent.toLowerCase();
return /iphone|ipad|ipod/.test( userAgent );
}
// Detects if device is in standalone mode
const isInStandaloneMode = () => ('standalone' in window.navigator) && (window.navigator.standalone);
// Checks if should display install popup notification:
if (isIos() && !isInStandaloneMode()) {
var iosPrompt = $(".ios-prompt");
iosPrompt.show();
$(iosPrompt).click(function() {
iosPrompt.hide();
});
}
if ('serviceWorker' in navigator) {
if(!navigator.onLine){
var app_offline = $('.pwa_offline');
if(app_offline){
app_offline.show();
}
}
navigator.serviceWorker.register('/service_worker.js');
}
}else{
if (navigator.serviceWorker) {
navigator.serviceWorker.getRegistrations().then(function (registrations) {
_.each(registrations, function (swregistration) {
swregistration.unregister();
console.log('ServiceWorker removed Peacefully');
});
}).catch(function (error) {
console.log('Service worker unregistration failed: ', error);
});
}
}
});
});

View File

@@ -0,0 +1,20 @@
/** @odoo-module **/
import { UserMenu } from "@web/webclient/user_menu/user_menu";
var { patch } = require("web.utils");
var session = require("@web/session");
patch(UserMenu.prototype, "spiffy_theme_backend.appsMenuJs", {
setup() {
this._super();
// greeting
var current_time_hr = new Date().getHours().toLocaleString("en-US", { timeZone: session.session.user_context.tz });
if ((parseInt(current_time_hr) >= 6) && (parseInt(current_time_hr) < 12)){
var greeting = "Good Morning"
} else if ((parseInt(current_time_hr) >= 12) && parseInt(current_time_hr) <= 18) {
var greeting = "Good Afternoon"
} else {
var greeting = "Good Evening"
}
this.greeting = greeting
}
});

View File

@@ -0,0 +1,390 @@
odoo.define('spiffy_theme_backend.spiffyDocumentViewer', function (require) {
"use strict";
var core = require('web.core');
var Widget = require('web.Widget');
var QWeb = core.qweb;
var SCROLL_ZOOM_STEP = 0.1;
var ZOOM_STEP = 0.5;
var spiffyDocumentViewer = Widget.extend({
template: "spiffyDocumentViewer",
events: {
'click .o_download_btn': '_onDownload',
'click .o_viewer_img': '_onImageClicked',
'click .o_viewer_video': '_onVideoClicked',
'click .move_next': '_onNext',
'click .move_previous': '_onPrevious',
'click .o_rotate': '_onRotate',
'click .o_zoom_in': '_onZoomIn',
'click .o_zoom_out': '_onZoomOut',
'click .o_zoom_reset': '_onZoomReset',
'click .o_close_btn, .o_viewer_img_wrapper': '_onClose',
'click .o_print_btn': '_onPrint',
'DOMMouseScroll .o_viewer_content': '_onScroll', // Firefox
'mousewheel .o_viewer_content': '_onScroll', // Chrome, Safari, IE
'keydown': '_onKeydown',
'keyup': '_onKeyUp',
'mousedown .o_viewer_img': '_onStartDrag',
'mousemove .o_viewer_content': '_onDrag',
'mouseup .o_viewer_content': '_onEndDrag'
},
/**
* The documentViewer takes an array of objects describing attachments in
* argument, and the ID of an active attachment (the one to display first).
* Documents that are not of type image or video are filtered out.
*
* @override
* @param {Array<Object>} attachments list of attachments
* @param {integer} activeAttachmentID
*/
init: function (parent, attachments, activeAttachmentID) {
this._super.apply(this, arguments);
this.attachment = _.filter(attachments, function (attachment) {
var match = attachment.type === 'url' ? attachment.url.match("(youtu|.png|.jpg|.gif)") : attachment.mimetype.match("(image|video|application/pdf|text)");
if (match) {
attachment.fileType = match[1];
if (match[1].match("(.png|.jpg|.gif)")) {
attachment.fileType = 'image';
}
if (match[1] === 'youtu') {
var youtube_array = attachment.url.split('/');
var youtube_token = youtube_array[youtube_array.length-1];
if (youtube_token.indexOf('watch') !== -1) {
youtube_token = youtube_token.split('v=')[1];
var amp = youtube_token.indexOf('&')
if (amp !== -1){
youtube_token = youtube_token.substring(0, amp);
}
}
attachment.youtube = youtube_token;
}
return true;
}
});
this.activeAttachment = _.findWhere(attachments, {id: activeAttachmentID});
this.modelName = 'ir.attachment';
this._reset();
},
/**
* Open a modal displaying the active attachment
* @override
*/
start: function () {
this.$el.modal('show');
this.$el.on('hidden.bs.modal', _.bind(this._onDestroy, this));
this.$('.o_viewer_img').on("load", _.bind(this._onImageLoaded, this));
this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
return this._super.apply(this, arguments);
},
/**
* @override
*/
destroy: function () {
if (this.isDestroyed()) {
return;
}
this.$el.modal('hide');
this.$el.remove();
this._super.apply(this, arguments);
},
//--------------------------------------------------------------------------
// Private
//---------------------------------------------------------------------------
/**
* @private
*/
_next: function () {
var index = _.findIndex(this.attachment, this.activeAttachment);
index = (index + 1) % this.attachment.length;
this.activeAttachment = this.attachment[index];
this._updateContent();
},
/**
* @private
*/
_previous: function () {
var index = _.findIndex(this.attachment, this.activeAttachment);
index = index === 0 ? this.attachment.length - 1 : index - 1;
this.activeAttachment = this.attachment[index];
this._updateContent();
},
/**
* @private
*/
_reset: function () {
this.scale = 1;
this.dragStartX = this.dragstopX = 0;
this.dragStartY = this.dragstopY = 0;
},
/**
* Render the active attachment
*
* @private
*/
_updateContent: function () {
this.$('.o_viewer_content').html(QWeb.render('spiffyDocumentViewer.Content', {
widget: this
}));
this.$('.o_viewer_img').on("load", _.bind(this._onImageLoaded, this));
this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
this._reset();
},
/**
* Get CSS transform property based on scale and angle
*
* @private
* @param {float} scale
* @param {float} angle
*/
_getTransform: function(scale, angle) {
return 'scale3d(' + scale + ', ' + scale + ', 1) rotate(' + angle + 'deg)';
},
/**
* Rotate image clockwise by provided angle
*
* @private
* @param {float} angle
*/
_rotate: function (angle) {
this._reset();
var new_angle = (this.angle || 0) + angle;
this.$('.o_viewer_img').css('transform', this._getTransform(this.scale, new_angle));
this.$('.o_viewer_img').css('max-width', new_angle % 180 !== 0 ? $(document).height() : '100%');
this.$('.o_viewer_img').css('max-height', new_angle % 180 !== 0 ? $(document).width() : '100%');
this.angle = new_angle;
},
/**
* Zoom in/out image by provided scale
*
* @private
* @param {integer} scale
*/
_zoom: function (scale) {
if (scale > 0.5) {
this.$('.o_viewer_img').css('transform', this._getTransform(scale, this.angle || 0));
this.scale = scale;
}
this.$('.o_zoom_reset').add('.o_zoom_out').toggleClass('disabled', scale === 1);
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {MouseEvent} e
*/
_onClose: function (e) {
e.preventDefault();
this.destroy();
},
/**
* When popup close complete destroyed modal even DOM footprint too
*
* @private
*/
_onDestroy: function () {
this.destroy();
},
/**
* @private
* @param {MouseEvent} e
*/
_onDownload: function (e) {
e.preventDefault();
window.location = '/web/content/' + this.modelName + '/' + this.activeAttachment.id + '/' + 'datas' + '?download=true';
},
/**
* @private
* @param {MouseEvent} e
*/
_onDrag: function (e) {
e.preventDefault();
if (this.enableDrag) {
var $image = this.$('.o_viewer_img');
var $zoomer = this.$('.o_viewer_zoomer');
var top = $image.prop('offsetHeight') * this.scale > $zoomer.height() ? e.clientY - this.dragStartY : 0;
var left = $image.prop('offsetWidth') * this.scale > $zoomer.width() ? e.clientX - this.dragStartX : 0;
$zoomer.css("transform", "translate3d("+ left +"px, " + top + "px, 0)");
$image.css('cursor', 'move');
}
},
/**
* @private
* @param {MouseEvent} e
*/
_onEndDrag: function (e) {
e.preventDefault();
if (this.enableDrag) {
this.enableDrag = false;
this.dragstopX = e.clientX - this.dragStartX;
this.dragstopY = e.clientY - this.dragStartY;
this.$('.o_viewer_img').css('cursor', '');
}
},
/**
* On click of image do not close modal so stop event propagation
*
* @private
* @param {MouseEvent} e
*/
_onImageClicked: function (e) {
e.stopPropagation();
},
/**
* Remove loading indicator when image loaded
* @private
*/
_onImageLoaded: function () {
this.$('.o_loading_img').hide();
},
/**
* Move next previous attachment on keyboard right left key
*
* @private
* @param {KeyEvent} e
*/
_onKeydown: function (e){
switch (e.which) {
case $.ui.keyCode.RIGHT:
e.preventDefault();
this._next();
break;
case $.ui.keyCode.LEFT:
e.preventDefault();
this._previous();
break;
}
},
/**
* Close popup on ESCAPE keyup
*
* @private
* @param {KeyEvent} e
*/
_onKeyUp: function (e) {
switch (e.which) {
case $.ui.keyCode.ESCAPE:
e.preventDefault();
this._onClose(e);
break;
}
},
/**
* @private
* @param {MouseEvent} e
*/
_onNext: function (e) {
e.preventDefault();
this._next();
},
/**
* @private
* @param {MouseEvent} e
*/
_onPrevious: function (e) {
e.preventDefault();
this._previous();
},
/**
* @private
* @param {MouseEvent} e
*/
_onPrint: function (e) {
e.preventDefault();
var src = this.$('.o_viewer_img').prop('src');
var script = QWeb.render('PrintImage', {
src: src
});
var printWindow = window.open('about:blank', "_new");
printWindow.document.open();
printWindow.document.write(script);
printWindow.document.close();
},
/**
* Zoom image on scroll
*
* @private
* @param {MouseEvent} e
*/
_onScroll: function (e) {
var scale;
if (e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) {
scale = this.scale + SCROLL_ZOOM_STEP;
this._zoom(scale);
} else {
scale = this.scale - SCROLL_ZOOM_STEP;
this._zoom(scale);
}
},
/**
* @private
* @param {MouseEvent} e
*/
_onStartDrag: function (e) {
e.preventDefault();
this.enableDrag = true;
this.dragStartX = e.clientX - (this.dragstopX || 0);
this.dragStartY = e.clientY - (this.dragstopY || 0);
},
/**
* On click of video do not close modal so stop event propagation
* and provide play/pause the video instead of quitting it
*
* @private
* @param {MouseEvent} e
*/
_onVideoClicked: function (e) {
e.stopPropagation();
var videoElement = e.target;
if (videoElement.paused) {
videoElement.play();
} else {
videoElement.pause();
}
},
/**
* @private
* @param {MouseEvent} e
*/
_onRotate: function (e) {
e.preventDefault();
this._rotate(90);
},
/**
* @private
* @param {MouseEvent} e
*/
_onZoomIn: function (e) {
e.preventDefault();
var scale = this.scale + ZOOM_STEP;
this._zoom(scale);
},
/**
* @private
* @param {MouseEvent} e
*/
_onZoomOut: function (e) {
e.preventDefault();
var scale = this.scale - ZOOM_STEP;
this._zoom(scale);
},
/**
* @private
* @param {MouseEvent} e
*/
_onZoomReset: function (e) {
e.preventDefault();
this.$('.o_viewer_zoomer').css("transform", "");
this._zoom(1);
},
});
return spiffyDocumentViewer;
});

View File

@@ -0,0 +1,79 @@
#myModal{
top:36px;
background-color: rgba(0, 0, 0, 0.7);
position: fixed;
left: 0;
z-index: 1057;
display: none;
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
outline: 0;
.modal-dialog{
padding:0 !important;
height: calc(100% - 100px);
pointer-events: all;
.attch-modal-content {
color: var(--biz-theme-body-text-color) !important;
.attch-viewer-header{
position: fixed;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.75) !important;
color: #ced4da !important;
width: 100% !important;
display: flex;
align-items: center;
justify-content: space-between;
.image_filename_div{
}
.download_clsoe_div{
display: flex;
a{
color: #ced4da !important;
}
}
}
.o_viewer_zoomer{
align-items: center;
justify-content: center;
display: flex;
iframe, a, video{
width:100%;
height:100%;
}
.o_viewer_img{
background-color: black;
max-height: 100%;
}
}
.o_viewer_toolbar{
justify-content: center;
bottom: 0;
a{
background-color: var(--AttachmentViewer_toolbarButton-background-color, #343a40);
color: #fff;
}
}
.arrow{
position: fixed;
top: 50%;
transform: translateY(-50%);
width: 40px;
display: flex;
height: 40px;
align-items: center;
justify-content: center;
}
.move_previous{
left: 15px !important;
}
.move_next{
right: 15px !important;
}
}
}
}

View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="spiffyDocumentViewer.Content">
<div class="o_viewer_content h-100">
<t t-set="model" t-value="widget.modelName"/>
<div class="attch-viewer-header">
<div class="image_filename_div ms-2">
<span class="o_image_caption">
<i class="fa fa-picture-o mr8" t-if="widget.activeAttachment.fileType == 'image'" role="img" aria-label="Image" title="Image"/>
<i class="fa fa-file-text mr8" t-if="widget.activeAttachment.fileType == 'application/pdf'" role="img" aria-label="PDF file" title="PDF file"/>
<i class="fa fa-video-camera mr8" t-if="widget.activeAttachment.fileType == 'video'" role="img" aria-label="Video" title="Video"/>
<span class="o_viewer_document_name" t-esc="widget.activeAttachment.name"/>
</span>
</div>
<div class="download_clsoe_div">
<a class="o_download_btn o_document_viewer_topbar_button btn" href="#" title="Download">
<i class="fa fa-fw fa-download" role="img" aria-label="Download"/>
<span class="d-none d-md-inline ml-2">Download</span>
</a>
<a role="button" href="#" class="o_close_btn o_document_viewer_topbar_button btn" title="Close">
<i class="fa fa-fw fa-close" role="img" aria-label="Close"/>
</a>
</div>
</div>
<div class="o_viewer_img_wrapper h-100">
<div class="o_viewer_zoomer h-100">
<t t-if="widget.activeAttachment.fileType === 'image'">
<div class="o_loading_img text-center">
<i class="fa fa-circle-o-notch fa-spin text-gray-light fa-3x fa-fw" role="img" aria-label="Loading" title="Loading"/>
</div>
<t t-set="unique" t-value="widget.activeAttachment.checksum ? widget.activeAttachment.checksum.slice(-8) : ''"/>
<img class="o_viewer_img img-fluid" t-attf-src="/web/image/#{widget.activeAttachment.id}?unique=#{unique}&amp;model=#{model}" alt="Viewer"/>
</t>
<iframe t-if="widget.activeAttachment.fileType == 'application/pdf'" class="o_viewer_pdf" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{widget.activeAttachment.id}?model%3D#{model}%26filename%3D#{window.encodeURIComponent(widget.activeAttachment.name)}" />
<iframe t-if="(widget.activeAttachment.fileType || '').indexOf('text') !== -1" class="o_viewer_text" t-attf-src="/web/content/#{widget.activeAttachment.id}?model=#{model}" />
<iframe t-if="widget.activeAttachment.fileType == 'youtu'" class="o_viewer_text" allow="autoplay; encrypted-media" width="560" height="315" t-attf-src="https://www.youtube.com/embed/#{widget.activeAttachment.youtube}"/>
<video t-if="widget.activeAttachment.fileType == 'video'" class="o_viewer_video" controls="controls">
<source t-attf-src="/web/image/#{widget.activeAttachment.id}?model=#{model}" t-att-data-type="widget.activeAttachment.mimetype"/>
</video>
</div>
</div>
<div t-if="widget.activeAttachment.fileType == 'image'" class="o_viewer_toolbar btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<a role="button" href="#" class="o_viewer_toolbar_btn btn o_zoom_in" data-toggle="tooltip" title="Zoom In"><i class="fa fa-fw fa-plus" role="img" aria-label="Zoom In"/></a>
<a role="button" href="#" class="o_viewer_toolbar_btn btn o_zoom_reset disabled" data-toggle="tooltip" title="Reset Zoom"><i class="fa fa-fw fa-search" role="img" aria-label="Reset Zoom"/></a>
<a role="button" href="#" class="o_viewer_toolbar_btn btn o_zoom_out disabled" data-toggle="tooltip" title="Zoom Out"><i class="fa fa-fw fa-minus" role="img" aria-label="Zoom Out"/></a>
</div>
<div class="btn-group" role="group">
<a role="button" href="#" class="o_viewer_toolbar_btn btn o_rotate" data-toggle="tooltip" title="Rotate"><i class="fa fa-fw fa-repeat" role="img" aria-label="Rotate"/></a>
</div>
<div class="btn-group" role="group">
<a role="button" href="#" class="o_viewer_toolbar_btn btn o_print_btn" data-toggle="tooltip" title="Print"><i class="fa fa-fw fa-print" role="img" aria-label="Print"/></a>
<a role="button" href="#" class="o_viewer_toolbar_btn btn o_download_btn" data-toggle="tooltip" title="Download"><i class="fa fa-fw fa-download" role="img" aria-label="Download"/></a>
</div>
</div>
</div>
</t>
<!--
@param {mail.DocumentViewer} widget
-->
<t t-name="spiffyDocumentViewer">
<div class="modal o_modal_fullscreen" id="myModal">
<div class="modal-dialog modal-lg">
<div class="attch-modal-content h-100">
<t class="o_document_viewer_content_call" t-call="spiffyDocumentViewer.Content" />
<t t-if="widget.attachment.length !== 1">
<a class="arrow arrow-left move_previous" href="#">
<span class="fa fa-chevron-left" role="img" aria-label="Previous" title="Previous"/>
</a>
<a class="arrow arrow-right move_next" href="#">
<span class="fa fa-chevron-right" role="img" aria-label="Next" title="Next"/>
</a>
</t>
</div>
</div>
</div>
</t>
<t t-name="PrintImage">
<html>
<head>
<script>
function onload_img() {
setTimeout('print_img()', 10);
}
function print_img() {
window.print();
window.close();
}
</script>
</head>
<body onload='onload_img()'>
<img t-att-src='src' alt=""/>
</body>
</html>
</t>
</templates>