';
if (itemShowBadgeMode == BADGE_ISCART_WITHCOUNT) {
html += '
';
if( cartCount == 0 || cartCount == "" ) {
document.documentElement.style.setProperty('--cart-count-number', '');
}else {
document.documentElement.style.setProperty('--cart-count-number', `"${cartCount}"`);
}
}
html += itemMedia(
item['icon'],
item['image'],
naviman_domain,
getStyleExtIcon(itemExtIconColor, itemExtIconSize, itemExtIconboxStyle, getIconBoxPaddingTop( getExtVariable(item, "iconboxpadding", "") )),
//getIconBoxPaddingTop( getExtVariable(item, "iconboxpadding", "") ),
getExtVariable(item, "iconboxpadding", ""),
itemExtIconSize,
getStyleExtAlign(itemExtAlign),
seoUrl,
item["name"]
);
var divInfo = '
'; // inner
if (itemIsParent)
if( getExtVariable(item, "fullexpand", "") == "1" ) {
html += generateMenu_Children_FullExpand(item["children"], naviItem, data,
{
"Animation": getExtVariable(item, "submenuanimation", ""),
"Background": getExtVariable(item, "submenubackgroundcolor", ""),
"BackgroundImage": getExtVariable(item, "submenubackgroundimage", ""),
},
isNaviSection,
section_setting,
defaultValue(data["setting"]['submenuFullExpandWidth'], ""),
defaultValue(item['fullexpandwidth'], ""),
menuKind
);
}else {
var childrenLevel = 2;
html += generateMenu_Children(
item["children"],
naviItem,
data,
{
"Animation": getExtVariable(item, "submenuanimation", ""),
"Background": getExtVariable(item, "submenubackgroundcolor", ""),
"BackgroundImage": getExtVariable(item, "submenubackgroundimage", ""),
},
isNaviSection,
section_setting,
"", // otherClass
childrenLevel,
menuKind
);
}
html += '';
/*** ENDOF: Đoạn mã để draw code tất tất cả kind of menu **********************************/
});
html += '';
html += scrollMobileDivClose;
return html;
} // generateMenu - level 1
/******************************************************************************************************************/
var getAttr = function ( attr ) {
if( attr == "" )
return "";
var attrArray = parseAttributes(decodeQuery( attr ));
if( attrArray.length == 0 )
return "";
return formatAttributes( attrArray );
}
var getExtHeight = function ( heightfix ) {
if( heightfix == "" )
return "";
return ' height: ' + String(heightfix).strReplace("px", " ").strReplace("pt", " ") + 'px; ';
}
var getDividerStyles = function ( level = 1, itemDivider, itemExtDiver, setting, menuKind ) {
if (itemDivider != 1)
return "";
var styles = ' style="';
var isOnMobile = window.innerWidth <= 768;
var dividerDirection = "right-";
if( level == 1 ) { // Nếu là level 1 thì chia một số trường hợp
if( menuKind == NAVIGLOBAL['MENU_KINDS']['STICKY_TABBAR']
/*
|| menuKind == NAVIGLOBAL['MENU_KINDS']['STICKY_FAB_SUPPORT'] /* Trường hợp STICKY_FAB_SUPPORT thực tế ko xảy ra vì ko có chọn vị trí */
) {
if (isOnMobile) {
if (
setting['mobilePosition'] == NAVIGLOBAL['MOBILE_POSITION']['RIGHT_CENTER'] ||
setting['mobilePosition'] == NAVIGLOBAL['MOBILE_POSITION']['LEFT_CENTER'] ||
setting['mobilePosition'] == NAVIGLOBAL['MOBILE_POSITION']['RIGHT_BOTTOM'] ||
setting['mobilePosition'] == NAVIGLOBAL['MOBILE_POSITION']['LEFT_BOTTOM']
) dividerDirection = "bottom-";
}
else {
if (
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_TOP'] ||
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_TOP'] ||
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_FULL_TOP'] ||
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_FULL_CENTER'] ||
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_FULL_TOP'] ||
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_FULL_CENTER']
) dividerDirection = "bottom-";
}
}
if( menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE'])
dividerDirection = "bottom-";
/* Phần này dành cho các FAB bên trái và bên phải phải- đã không còn ở trong thư viện nữa rồi ************/
if( menuKind == NAVIGLOBAL['MENU_KINDS']['STICKY_FAB_SUPPORT']) {
if (isOnMobile) {
if (
setting['mobilePosition'] == NAVIGLOBAL['MOBILE_POSITION']['RIGHT_CENTER'] ||
setting['mobilePosition'] == NAVIGLOBAL['MOBILE_POSITION']['LEFT_CENTER']
) dividerDirection = "bottom-";
}
else {
if (
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_TOP'] ||
setting['desktopPosition'] == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_TOP']
) dividerDirection = "bottom-";
}
}
/* Phần này dành cho các FAB bên trái và bên phải phải- đã không còn ở trong thư viện nữa rồi **********/
} else // Nếu là level 2,3 thì chỉ có một trường hợp ngang thôi.
dividerDirection = "bottom-";
if( itemExtDiver["dividercolor"] != "" )
styles += 'border-'+ dividerDirection +'color:' + itemExtDiver["dividercolor"] + ';';
if( itemExtDiver["dividersize"] != "" )
styles += 'border-'+ dividerDirection +'width:' + String(itemExtDiver["dividersize"]).strReplace("px", "").strReplace("pt", "") + 'px;';
if( itemExtDiver["dividertype"] != "" )
styles += 'border-'+ dividerDirection +'style:' + itemExtDiver["dividertype"] + ';';
styles += '"';
return styles;
}
var getSubmenuClasses = function (itemExtSubmenu) {
if( itemExtSubmenu["Animation"] != "" )
return getAnimationClass( itemExtSubmenu["Animation"] );
return "";
}
var getSubmenuStyles = function (itemExtSubmenu, data) {
/*var styles = ' style="';
if( itemExtSubmenu["Background"] != "" )
styles += 'background-color:' + itemExtSubmenu["Background"] + ';';
if( itemExtSubmenu["BackgroundImage"] != "" )
styles += ' background-image: url('+ itemExtSubmenu["BackgroundImage"] +'); background-size: cover;';
styles += '"';
return styles;*/
return getStyleExtBackground(itemExtSubmenu["Background"], itemExtSubmenu["BackgroundImage"], data, 2);
}
var getIconBoxPaddingTop = function (iconBoxPadding) {
var itemExtIconBox = Helper.HTML.parsePaddingMargin(iconBoxPadding);
return itemExtIconBox.top;
}
var getIconboxStyle = function ( color, padding, radius ) {
if( color == "" )
return "";
var styleCSS = "";
styleCSS += 'background-color:' + color + ';';
if( padding != "") {
styleCSS += Helper.HTML.formatPaddingTRBL(Helper.HTML.parsePaddingMargin(padding));
styleCSS += ' display: inline-block; ';
}
if( radius != "")
styleCSS += 'border-radius:' + String(radius).strReplace("px", "").strReplace("pt", "") + 'px';
return styleCSS;
}
var getItemExClassOfKind = function ( itemKind ) {
if( itemKind == NAVIGLOBAL['ITEM_KINDS']['ICON_IMAGE_TEXT'] )
return " kind-icon-image-text ";
if( itemKind == NAVIGLOBAL['ITEM_KINDS']['GROUP_TITLE'] )
return " kind-group-title ";
if( itemKind == NAVIGLOBAL['ITEM_KINDS']['BLANK_SPACE'] )
return " kind-blank-space ";
if( itemKind == NAVIGLOBAL['ITEM_KINDS']['BIG_IMAGE_TEXT'] )
return " kind-big-image-text ";
if( itemKind == NAVIGLOBAL['ITEM_KINDS']['CUSTOM_HTML'] )
return " kind-custom-html ";
if( itemKind == NAVIGLOBAL['ITEM_KINDS']['BUTTON'] )
return " kind-button ";
}
var getPublishClassed = function ( itemExtIsPublished, itemExtHideWhenLogined, itemExtShowWhenLogined, itemExtAttr ) {
var combinedClass = " ";
if( itemExtIsPublished != 1 )
combinedClass += "publish-hide ";
if( itemExtHideWhenLogined == 1 )
combinedClass += "publish-hide-logined ";
if( itemExtShowWhenLogined == 1 )
combinedClass += "publish-show-logined ";
if( itemExtAttr != "" ) {
var hidePages = Menu.Item.getHidePages(parseAttributes(decodeQuery( itemExtAttr )));
if( hidePages.length != 0 ) {
let currentTemplate = getCurrentTemplate();
if (hidePages.includes(currentTemplate))
combinedClass += "publish-hide ";
}
}
if( combinedClass.trim() == "" )
return "";
return combinedClass;
}
var getAnimationClass = function ( itemExtAnimation ) {
if( itemExtAnimation != "" )
return " animate__animated " + itemExtAnimation;
return "";
}
var collectStyles = function(styleArray) {
let combinedStyle = ' style="';
for (var i = 0; i < styleArray.length; i++) {
if (!styleArray[i]) continue; // Bỏ qua nếu là null, undefined hoặc chuỗi rỗng
let styles = styleArray[i].replace(/style="|"/g, '');
combinedStyle += styles;
}
combinedStyle += '"';
return removeExtraSpaces(combinedStyle);
};
var collectClasses = function (classesArray) {
if (!Array.isArray(classesArray) || classesArray.length === 0) {
return '';
}
let combinedClasses = '';
for (let i = 0; i < classesArray.length; i++) {
if (typeof classesArray[i] !== 'string' || !classesArray[i].trim()) continue; // Bỏ qua giá trị không phải string hoặc rỗng
let cleanedClasses = classesArray[i].split(/[ ,;|.]+/).filter(Boolean).join(' ');
combinedClasses += cleanedClasses + ' ';
}
return removeExtraSpaces(combinedClasses.trim());
};
var getStyleExtAlign = function (itemExtAlign) {
var style = ' style="';
if( itemExtAlign != "inherit") style += ' text-align: '+ itemExtAlign +'; ';
style += '" ';
if( style.trim() == 'style=""' )
return '';
return style;
}
var getClassesExtAlign = function (itemExtAlign) {
var style = ' ';
if( itemExtAlign != "inherit") style += ' align-' + itemExtAlign + ' ';
if( style.trim() == 'style=""' )
return '';
return style;
}
var getStyleExtBackground = function (itemExtBackgroundColor, itemExtBackgroundImage, data, menuLevel = 1) {
var style = ' style="';
if (itemExtBackgroundImage != "") {
if( itemExtBackgroundImage.includes("?") ) {
// Xử lý duy nhất trường hợp có opacity cho background Image
var bg = itemExtBackgroundImage.split("?");
var bgImage = bg[0];
var bgOpacity = parseInt( bg[1] );
if( bgOpacity != 0 ) {
if( itemExtBackgroundColor == "") {
if(menuLevel == 1)
itemExtBackgroundColor = data["setting"]['backgroundColor'];
else
itemExtBackgroundColor = data["setting"]['submenuBackgroundColor'];
}
style += ' background-image: url(\'' + bgImage + '\'); background-size: cover; background-position: initial; ';
style += ' background-color: ' + hexToRgba(itemExtBackgroundColor, 1 - (bgOpacity / 100)) + '; background-blend-mode: hue; ';
}else {
style += ' background-color: '+ itemExtBackgroundColor +'; ';
}
}else {
style += ' background-color: '+ itemExtBackgroundColor +'; ';
style += ' background-image: url('+ itemExtBackgroundImage +'); background-size: cover;';
}
}else
{ // Nếu ko có background thì dùng màu bình thường.
if (itemExtBackgroundColor != "")
style += ' background-color: '+ itemExtBackgroundColor +'; ';
}
/*
if( itemExtBackgroundColor != "") style += ' background-color: '+ itemExtBackgroundColor +'; ';
if( itemExtBackgroundImage != "") style += ' background-image: url('+ itemExtBackgroundImage +'); background-size: cover;';
*/
style += '" ';
if( style.trim() == 'style=""' )
return '';
return style;
}
var getStyleExtText = function (itemExtTextColor, itemExtTextSize) {
var style = ' style="';
if( itemExtTextColor != "") style += ' color: '+ itemExtTextColor +'; ';
if( itemExtTextSize != "") style += ' font-size: '+ itemExtTextSize +'px; ';
style += '" ';
if( style.trim() == 'style=""' )
return '';
return style;
}
var getStyleExtIcon = function (itemExtIconColor, itemExtIconSize, itemExtIconboxStyle = "", itemExtIconBoxPaddingTop = 0) {
var style = ' style="';
if( itemExtIconColor != "") style += ' color: '+ itemExtIconColor +'; ';
if( itemExtIconSize != "") {
style += ' font-size: ' + itemExtIconSize + 'px;';
// Logic: Nếu có iconBox thì sẽ ko fix cái chiều cao của icon
if( itemExtIconBoxPaddingTop == 0 )
style += ' height: ' + itemExtIconSize + 'px; ';
/*if( itemExtIconBoxPaddingTop != 0 )
style += ' z-index:10; ';*/
}
if( itemExtIconboxStyle != "" ) style += itemExtIconboxStyle;
style += '" ';
if( style.trim() == 'style=""' )
return '';
return style;
}
var getExtPosition = function (item) {
var position = getExtVariable(item, "position", 1);
var style = ' style="';
/** Logic: Nếu như mà width layout ko phải là fix hay là hug thì position không thêm vào ko sẽ bị lỗi */
var widthLayout = getExtVariable(item, "widthlayout", 1);
if( widthLayout != 14 && widthLayout != 20 ) {
return "";
}
/******************************************************************************************************/
if (position == 2)
style += "position: absolute; margin-left: auto; margin-right: auto; left: 0; right: 0; text-align: center;z-index: 0; ";
if (position == 3)
style += "position: absolute; right: 0; text-align: right; ";
if (position == 4)
style += "position: absolute; left: 0; text-align: left; ";
style += '" ';
if (style.trim() == 'style=""')
return '';
return style;
}
var getExtWidth = function( item ) {
var widthLayout = getExtVariable(item, "widthlayout", 1);
var itemExtWidth = "";
if( widthLayout == 1 ) itemExtWidth = "";
if( widthLayout == 2 ) itemExtWidth = "8.3333333333%";
if( widthLayout == 3 ) itemExtWidth = "16.6666666666%";
if( widthLayout == 4 ) itemExtWidth = "25%";
if( widthLayout == 5 ) itemExtWidth = "33.3333333333%";
if( widthLayout == 6 ) itemExtWidth = "41.6666666666%";
if( widthLayout == 7 ) itemExtWidth = "50%";
if( widthLayout == 8 ) itemExtWidth = "58.3333333333%";
if( widthLayout == 9 ) itemExtWidth = "66.6666666666%";
if( widthLayout == 10 ) itemExtWidth = "75%";
if( widthLayout == 11 ) itemExtWidth = "83.3333333333%";
if( widthLayout == 12 ) itemExtWidth = "91.6666666666%";
if( widthLayout == 13 ) itemExtWidth = "100%";
if( widthLayout == 15 ) itemExtWidth = "10%";
if( widthLayout == 16 ) itemExtWidth = "20%";
if( widthLayout == 17 ) itemExtWidth = "50%";
if( widthLayout == 18 ) itemExtWidth = "100%";
if( widthLayout == 14 ) {
var widthfix = getExtVariable(item, "widthfix", "");
if (widthfix != "")
itemExtWidth = String(widthfix).replace("pt", "").replace("px", "") + "px";
}
if( widthLayout == 20 ) itemExtWidth = "auto";
var itemExtWidthStyle = "";
var itemExtWidthClass = "";
// Nếu widthLayout != 0 (tức là automation) thì sẽ có width: xxx.
if( itemExtWidth != "" ) {
itemExtWidthStyle = ' width: ' + itemExtWidth + ';';
itemExtWidthClass = ' widthfix ';
if( itemExtWidth == "auto" )
itemExtWidthClass += ' widthauto ';
}
return {
'width': itemExtWidth,
'style' : itemExtWidthStyle,
'class' : itemExtWidthClass
};
}
function isString(value) {
return typeof value === 'string' || value instanceof String
}
var getExtVariable = function( item, varName, defaultValue ) {
if( item[varName] != null ) {
var val = item[varName];
if( isString(val) )
val = val.trim();
val = platformValue( val );
return val;
}
return defaultValue;
}
var getItemHighlight = function(data) { // Chỉ phục vụ cho loại highlight
var highLightItem = 0;
if (data["setting"]['layout'] == NAVIGLOBAL['LAYOUT']['HIGHLIGHT']) {
if (data["dragdrop"].length == 7 || data["dragdrop"].length == 5 || data["dragdrop"].length == 3)
highLightItem = (data["dragdrop"].length + 1) / 2;
}
return highLightItem;
}
var getItemKind = function (item) {
var itemKind = 1;
if( item["kind"] != null )
itemKind = item["kind"];
return itemKind;
}
var getItemDivider = function (item) {
var divider = 0;
if( item["divider"] != null )
divider = item["divider"];
return divider;
}
var getItemIsParent = function( item ) {
var itemIsParent = false;
if (typeof (item["children"]) !== 'undefined')
if (item["children"].length > 0)
itemIsParent = true;
return itemIsParent;
}
var getItemShowBadgeMode = function (item) {
var itemShowBadgeMode = BADGE_HIDE;
if (item["badge"] == 1) {
if( isHadValue (item["badgeiscart"]) ) {
if (item["badgeiscart"] == 0)
itemShowBadgeMode = BADGE_HIDE;
else {
itemShowBadgeMode = BADGE_ISCART_WITHCOUNT;
}
}else
itemShowBadgeMode = BADGE_DOT;
}
return itemShowBadgeMode;
}
var getItemClickTelSMS = function (isTel, isSMS, item_url) {
var html = " ";
if( isTel || isSMS ) {
html += '
';
}
return html;
}
var getItemExClassOfBadge = function (item) {
var item_css = " ";
if (item["badge"] == 1) {
item_css += " item_badge";
if( isHadValue (item["badgeiscart"]) ) {
if (item["badgeiscart"] == 1) {
item_css += " item_badge_withcount ";
if (item["badgecartcount"] == 1)
item_css += "";
else
item_css += " item_badge_withcount item_badge_withcount_hide";
}
}
}
else
item_css += ""; // Do nothing
return item_css;
};
var getChildExClassOfBadge = function (child) {
var child_css = " ";
if (child["badge"] == 1) {
child_css += " child_badge";
if( isHadValue (child["badgeiscart"]) ) {
if (child["badgeiscart"] == 1) {
child_css += " child_badge_withcount ";
if (child["badgecartcount"] == 1)
child_css += "";
else
child_css += " child_badge_withcount child_badge_withcount_hide";
}
}
}
else
child_css += ""; // Do nothing
return child_css;
};
var isOpenInbox = function ( item_url ) {
if( item_url.length == 10 ) // open:Inbox
if( item_url.substring(0, 10).toLowerCase() == "open:inbox" )
return true;
return false;
};
var isItemTel = function ( item_url ) {
if( item_url.length >= 4 ) // tel
if( item_url.substring(0, 4).toLowerCase() == "tel:" )
return true;
return false;
};
var isItemSMS = function ( item_url ) {
if( item_url.length >= 4 ) // sms
if( item_url.substring(0, 4).toLowerCase() == "sms:" )
return true;
return false;
}
var isNaviSection = false;
response.forEach((naviItem) => {
isNaviSection = (embed_id != '' );
/* Thêm vào 1 Queue để đảm bảo không lặp lại */
addNaviItemToQueue(naviItem);
//*********************************************************************** */
// TODO: HÀM NÀY CÓ THỂ TRẢ VỀ NULL NẾU NHƯ SHOPINFO CHƯA SẴN SÀNG DẪN ĐẾN:
// 1. HIỂN THỊ CÓ THỂ LỖI
// 2. CLASS VỚI TÊN NÀY CÓ THỂ LỖI
//*********************************************************************** */
var menuKind = fixMenuKind;
if( menuKind == 0 ) // Nếu như ko phải là simulator
menuKind = naviItem["menuKind"];
var menuKindClass = getMenuKindStringById(menuKind);
var isDisplayed = true;
/*****************************************************************************************************************/
if( menuKindClass == "CONTEXT_SLIDE" ) {
if( !Helper.Env.isBackendMode() ) {
Menu.Context.checkTriggerIDClass(isDisplayed, naviItem);
isDisplayed = Menu.Common.checkPlatformMode(isDisplayed, naviItem);
}
if( !Menu.Context.isDisplayTrigger(menuKindClass, naviItem) )
isDisplayed = false;
}
/*****************************************************************************************************************/
if (["STICKY_TABBAR", "STICKY_MOBILE_HEADER", "STICKY_FAB_SUPPORT"].includes(menuKindClass)) {
if (!Helper.Env.isBackendMode()) {
isDisplayed = Menu.Common.checkContainKeywords(isDisplayed, naviItem);
isDisplayed = Menu.Sticky.checkStickyDisplay(isDisplayed, naviItem, isNaviSection);
isDisplayed = Menu.Common.checkPlatformMode(isDisplayed, naviItem);
}
}
/*****************************************************************************************************************/
var isPublishToPlace = false;
var publishToPlaceClass = "";
if ( ["SECTION_MOBILE_HEADER", "SECTION_MOBILE_MEGAMENU", "SECTION_MOBILE_GRID", "SECTION_MOBILE_BANNER", "SECTION_DESKTOP_MEGAMENU"].includes(menuKindClass) ) {
if (!Helper.Env.isBackendMode()) {
isDisplayed = Menu.Common.checkContainKeywords(isDisplayed, naviItem);
isDisplayed = Menu.Common.checkPlatformMode(isDisplayed, naviItem);
if (isDisplayed) {
isPublishToPlace = Menu.Section.checkPublicToPlace(naviItem);
isNaviSection = isPublishToPlace || isNaviSection;
}
isDisplayed = Menu.Section.checkSectionPublishWays(isDisplayed, naviItem, embed_id, isPublishToPlace);
}
}
/******** Nếu là backend mode thì sẽ không coi là Section, chỉ coi là nhúng bình thường thôi *******************/
if (Helper.Env.isBackendMode())
isNaviSection = false;
/*****************************************************************************************************************/
if( isDisplayed )
Helper.Debug.writeBeautifyConsoleLog( "\uD83D\uDE01 Navi+: " + naviItem["embed_id"] + " (" + menuKindClass + ") display: " + isDisplayed, "green" );
else
Helper.Debug.writeBeautifyConsoleLog( "Navi+: " + naviItem["embed_id"] + " (" + menuKindClass + ") display: " + isDisplayed, "red" );
// BẮT ĐẦU HIỂN THỊ NẾU ISDISPLAY ******************************************************************************
if (isDisplayed) {
let data = naviItem["data"];
Menu.Common.initHTMLAppOverlayClasses();
var embedMarginStyle = Menu.Section.getStyleSectionMargin(section_setting);
var attribute = "";
if( naviItem["data"]["setting"]["attribute"] != null )
attribute = formatAttributes(parseAttributes( naviItem["data"]["setting"]["attribute"] ));
if( isPublishToPlace == true ) {
publishToPlaceClass = " publishToPlace ";
}
var divNaviItem = '
';
/***************************************************************************************************************************
* Xử lý việc chèn menu vào đâu, mặc định là chèn vào naviman_app, còn nếu không thì chèn vào chỗ replace id
***************************************************************************************************************************/
if( isPublishToPlace == true ) {
var elsIdClass = naviItem["data"]["setting"]['publishToPlace'];
// Chọn tất cả các phần tử khớp với chuỗi
var els = document.querySelectorAll(elsIdClass);
// Lặp qua các phần tử được chọn
els.forEach(function(el) {
// Thêm logic xử lý với từng phần tử tại đây
debugModeLog("Found element:", el);
var tempElement = document.createElement('div');
divNaviItem = '
';
tempElement.innerHTML = divNaviItem;
// Lấy phần tử thực sự từ chuỗi divNaviItem
var newElement = tempElement.firstChild;
// publishToPlaceKind
var publishToPlaceKind = 1;
if( isHadValue( naviItem["data"]["setting"]['publishToPlaceKind'] ) )
publishToPlaceKind = naviItem["data"]["setting"]['publishToPlaceKind'];
if( publishToPlaceKind == "1" ) // replace
el.replaceWith(newElement);
if( publishToPlaceKind == "2" ) // insert after
el.insertAdjacentElement('afterend', newElement);
if( publishToPlaceKind == "3" ) // insert before
el.insertAdjacentElement('beforebegin', newElement);
});
}
// HÀM QUAN TRỌNG NHẤT: Chèn menu dạng sticky, section (tuỳ vào
bên ngoài nó thế nào) *************<><><>
if( isPublishToPlace == false ) {
naviman_app.insertAdjacentHTML('beforeend', divNaviItem);
}
/***************************************************************************************************************************
* Xử lý việc chèn menu vào đâu, mặc định là chèn vào naviman_app, còn nếu không thì chèn vào chỗ replace id
***************************************************************************************************************************/
var naviman_appItem = document.getElementById(naviItem["embed_id"]);
if (!naviman_appItem)
console.warn("Can not find (Maybe Insert/replace id be wrong):", naviItem["embed_id"]);
naviman_appItem.classList.add('naviman_layout' + data["setting"]['layout']);
generateCSS(naviman_appItem, naviItem["embed_id"], data["setting"], data["dragdrop"], isNaviSection, section_setting, menuKind);
// Add visit call to server by increasing the file count
if (!Helper.Env.isBackendMode())
jsonp(naviman_domain + 'ajax-main.php?action=updateVisit' + '&shop=' + shop).then(function(data){});
naviman_appItem.insertAdjacentHTML('beforeend',
generateMenu(data, naviItem, isNaviSection, section_setting, menuKind)
);
// Fix cho section
if( embed_id != "" && (section_setting['not_sticky'] == true || section_setting['not_sticky'] == "true" ) ) {
Menu.Section.fixCSS_ResetBotomTop( naviman_appItem, shop, naviItem["embed_id"], section_setting );
Menu.Section.fixCSS_Megamenu_desktop( naviman_appItem, shop, naviItem["embed_id"], section_setting, menuKind );
// Logic: Tìm đến section class gần nhất trên Shopify để đổi style -> Có thể có rủi ro nếu ko tìm thấy
if( isNaviSection )
Menu.Section.fixCSS_SectionParent( naviman_app, response[0], embed_id, section_setting, menuKind );
}
/* Chậm lại để cho CSS ổn định rồi thì mới hiện ra */
/*
setTimeout(() => {
var isStartVisibility = true;
if( Menu.Context.isDisplayTrigger(menuKindClass, naviItem) )
isStartVisibility = false;
if( Helper.Env.isBackendMode() )
isStartVisibility = true;
if( isStartVisibility ) {
Helper.closeAllDropdowns();
Helper.HTML.addStyleToHeader( '#' + naviItem["embed_id"] + ' { visibility: visible !important }');
}
}, 250);*/
Helper.waitForCssToLoad(() => {
var isStartVisibility = true;
if (Menu.Context.isDisplayTrigger(menuKindClass, naviItem))
isStartVisibility = false;
if (Helper.Env.isBackendMode())
isStartVisibility = true;
if (isStartVisibility) {
Helper.closeAllDropdowns(); // Đóng hết lại để đảm bảo ko có dropdown nào tự động mở
Helper.HTML.addStyleToHeader(
'#' + naviItem["embed_id"] + ' { visibility: visible !important }'
);
}
});
callbackPublicFunc_delay(drawBottomNav, naviItem["embed_id"]);
} // isDisplayed
});
debugModeLog(window.navimanData);
// Nếu như cùng lúc section và sticky cùng bật thì loại bỏ sticky
//MenuSection.fixTurnonBothSectionSticky( naviman_appItem, isNaviSection, naviItem["embed_id"] );
Menu.Section.hideDuplicateNavimanItems();
};
var Log = Log || {};
Log.saveLog = function(logShop, logToUrl, logFromUrl, logItemName, logEmbedId, logPlatform ) {
if( logToUrl == "#" ) {
console.log("Log: To URL is #, not saving log");
return;
}
let tranferData = {
shop: logShop,
to_url: logToUrl,
from_url: logFromUrl,
item_name: logItemName,
embed_id: logEmbedId,
platform: logPlatform
};
const params = new URLSearchParams(tranferData);
jsonp(naviman_domain + 'ajax-main.php?action=saveLog' + '&' + params.toString()).then(function(data){
});
};
var standalizeFuncWillVar = function (str) {
str = str.strReplace('"', '');
str = str.strReplace("'", "");
// 1. Add "" for var
let result = '';
let parenthesesStack = [];
for (let i = 0; i < str.length; i++) {
if (str[i] === '(' && (i === 0 || str[i - 1] !== '"')) {
result += str[i] + '"';
parenthesesStack.push('(');
} else if (str[i] === ')' && (i === str.length - 1 || str[i + 1] !== '"')) {
result += '"' + str[i];
if (parenthesesStack.length > 0 && parenthesesStack[parenthesesStack.length - 1] === '(') {
parenthesesStack.pop();
} else {
// Unbalanced parentheses
return null;
}
} else {
result += str[i];
}
}
// Check for unbalanced parentheses
if (parenthesesStack.length > 0) {
return null;
}
return result;
}
var checkClickOnHovermenu = function(event, item, is_parent, url, embed_id, isNaviSection) {
var eventType = event.type; // click or mouseenter
var setting = getSettingOfNaviman( embed_id );
var desktopHover = isSettingBeTrue(setting['desktopHover']);
if (window.innerWidth <= 768) desktopHover = false;
if( !desktopHover ) return;
if( eventType == "click" ) {
url = url.trim();
if( url == "" )
url = "#";
gotoUrl(event, item, false, url, embed_id, isNaviSection);
}
};
var gotoUrl = function (event, item, is_parent, url, embed_id, isNaviSection) {
var shopinfo = navihelper.windowVar.get('shopinfo');
var menuKind = getMenuKind(shopinfo, embed_id);
console.log("gotoUrl: " + url);
if (!is_parent) {
if (Helper.Env.isBackendMode()) {
if (url != "")
showSnackbar("Link to:
" + url + "");
return false;
}
// khoipn
let logShop = shopinfo["shop"];
let logFromUrl = window.location.href;
let logItemName = item.dataset.name;
let logEmbedId = embed_id; // Lỗi ở đây rồi
let logPlatform = "M";
if (window.innerWidth > 768)
logPlatform = "D";
let openNewTab = false;
if (url.toLowerCase().includes("@new")) {
openNewTab = true;
url = url.replace(/@new/gi, '');
}
if (url.substring(0, 13).toLowerCase() == "https://m.me/")
openNewTab = true;
if (url.substring(0, 14).toLowerCase() == "https://wa.me/")
openNewTab = true;
let logDomain = "https://" + window.location.hostname;
url = url.trim();
if (url == "") { // Home page
Log.saveLog(logShop, logDomain, logFromUrl, logItemName, logEmbedId, logPlatform);
if (openNewTab)
window.open(logDomain);
else
window.location.href = logDomain;
}
if (url == "#") { // Do nothing
Log.saveLog(logShop, url, logFromUrl, logItemName, logEmbedId, logPlatform);
return false;
}
if (url.length > 1) {
if (url.charAt(0) === "#") { // #gotoAnchor
let cleanUrl = logFromUrl.replace(/#.*$/, ""); // Xoá hash cũ nếu có
let logTo = cleanUrl + url;
Log.saveLog(logShop, logTo, logFromUrl, logItemName, logEmbedId, logPlatform);
if (window.location.hash === url) {
// Nếu hash mới trùng với hash hiện tại, xóa nó trước rồi đặt lại
window.history.replaceState(null, "", cleanUrl);
setTimeout(() => {
window.history.pushState(null, "", logTo);
}, 10);
} else {
window.history.pushState(null, "", logTo);
}
return;
}
if (url.length >= 4) // tel
if (url.substring(0, 4).toLowerCase() == "tel:") {
//window.open( url );
//window.location.href = url;
return false;
}
if (url.length >= 4) // sms
if (url.substring(0, 4).toLowerCase() == "sms:") {
//window.open( url );
//window.location.href = url;
return false;
}
if (url.length >= 5) // open
if (url.substring(0, 5).toLowerCase() == "open:") {
jsFunction = url.strReplace(':', '');
Log.saveLog(logShop, url, logFromUrl, logItemName, logEmbedId, logPlatform);
// Open NaviMenu
if (url.length >= 13)
if (url.substring(0, 13).toLowerCase() == "open:navimenu") {
const func = Menu.Context.splitTriggerFunction(jsFunction);
eval('naviman.' + func["functionName"] + '("' + func["variableName"] + '")');
return false;
}
// Handle ClickTo
if (url.length >= 12 && url.toLowerCase().startsWith("open:clickto")) {
const func = Menu.Context.splitTriggerFunction(jsFunction);
const params = func["variableName"].split(",");
const elementSelector = params[0].trim();
const direction = params[1] ? params[1].trim().toLowerCase() : null;
const clickAction = () => naviman.clickToElement(elementSelector);
if (direction === "down") {
naviman.scrollBottom();
setTimeout(clickAction, 1000);
} else if (direction === "up") {
naviman.scrollTop();
setTimeout(clickAction, 1000);
} else {
clickAction(); // Execute immediately if no scroll direction
}
return false;
}
// Handle FocusTo
if (url.length >= 12 && url.toLowerCase().startsWith("open:focusto")) {
const func = Menu.Context.splitTriggerFunction(jsFunction);
const params = func["variableName"].split(",");
const elementSelector = params[0].trim();
const direction = params[1] ? params[1].trim().toLowerCase() : null;
const focusAction = () => naviman.focusToElement(elementSelector);
if (direction === "down") {
naviman.scrollBottom();
setTimeout(focusAction, 1000);
} else if (direction === "up") {
naviman.scrollTop();
setTimeout(focusAction, 1000);
} else {
focusAction(); // Execute immediately if no scroll direction
}
return false;
}
// Open other functions such as: openMobileMenu
eval("naviman." + jsFunction)();
return false;
}
if (url.length >= 6) // share
if (url.substring(0, 6).toLowerCase() == "share:") {
jsFunction = url.strReplace(':', '');
Log.saveLog(logShop, url, logFromUrl, logItemName, logEmbedId, logPlatform);
eval("naviman." + jsFunction)();
return false;
}
if (url.length >= 7) // scroll
if (url.substring(0, 7).toLowerCase() == "scroll:") {
jsFunction = url.strReplace(':', '');
var isScrollOnPage = true;
if (url.length >= 10) if (url.substring(0, 10).toLowerCase() == "scroll:top")
isScrollOnPage = false;
if (url.length >= 13) if (url.substring(0, 13).toLowerCase() == "scroll:bottom")
isScrollOnPage = false;
if (isScrollOnPage)
jsFunction = standalizeFuncWillVar(jsFunction);
Log.saveLog(logShop, url, logFromUrl, logItemName, logEmbedId, logPlatform);
if (jsFunction.includes('(')) // Có biến
eval("naviman." + jsFunction);
else
eval("naviman." + jsFunction)();
return false;
}
if (url.length >= 7) // mailto
if (url.substring(0, 7).toLowerCase() == "mailto:") {
window.open(url);
return false;
}
if (url.length >= 11) // javascript
if (url.substring(0, 11).toLowerCase() == "javascript:") {
let jsFunction = url.substring(11, url.length);
jsFunction = jsFunction.strReplace('(', '').strReplace(')', '');
Log.saveLog(logShop, 'js/' + jsFunction, logFromUrl, logItemName, logEmbedId, logPlatform);
console.log("Call function: " + jsFunction);
eval(jsFunction)();
event.preventDefault(); // Ko có tác dụng mấy
return false;
}
let isHadDomain = false;
if (url.length >= 4)
if (url.substring(0, 4).toLowerCase() == "http")
isHadDomain = true;
if (!isHadDomain) {
if (url.charAt(0) != "/")
url = "/" + url;
url = logDomain + url;
}
Log.saveLog(logShop, url, logFromUrl, logItemName, logEmbedId, logPlatform);
if (openNewTab) {
if (url.substring(0, 14).toLowerCase() == "https://wa.me/") {
// TODO: Need to optimize
console.log("Fixed for Whats App");
/* Mình sẽ mở lại một tab mới bình thường để hiển thị What's App */
// window.open(url, "WhatsApp", "width=200,height=100");
openWhatsAppChat(url.substring(14, url.length));
} else
window.open(url);
} else
/* URL THÔNG THƯỜNG **********************************/
{
redirectToUrl(url);
}
}
} else {
// Kiểm tra nếu như hover chuột và có click thì chuyển theo link
checkClickOnHovermenu(event, item, is_parent, url, embed_id, isNaviSection);
if (item.classList.contains("child")) {
showLevel3Items_Common(item, isNaviSection, menuKind, embed_id);
showLevel3Items_Desktop(item, isNaviSection, menuKind, embed_id);
}
else
showLevel2Items(item, menuKind, embed_id);
}
// Tránh việc gọi ông con thì lại gọi thêm ông bố
event.stopPropagation();
};
var redirectToUrl = function (url) {
window.location.href = url;
// Nếu có dấu # thì reload sau 500ms
if (url.includes('#')) {
setTimeout(function () {
location.reload();
}, 500);
}
}
var openWhatsAppChat = function(phone, message = "") {
const isMobile = window.innerWidth <= 768;
const encodedMessage = encodeURIComponent(message);
const url = isMobile
? `https://wa.me/${phone}?text=${encodedMessage}`
: `https://api.whatsapp.com/send?phone=${phone}&text=${encodedMessage}`;
window.open(url, "_blank"); // luôn mở tab mới
};
var hideAllLevel3Items = function () {
document.querySelectorAll('.naviman_app ul.children ul.children').forEach((item) => {
item.style.display = "none";
});
document.querySelectorAll('.naviman_app ul.children ul.children').forEach((item) => {
item.style.display = "none";
});
};
var findIDofMenuItem = function (menuItem) {
if (menuItem == null)
return null;
if (menuItem.parentElement == null)
return null;
if (menuItem.classList.contains("naviItem"))
return menuItem.id;
return findIDofMenuItem(menuItem.parentElement);
}
var showLevel3Items_Common = function (menuItem, isNaviSection, menuKind, embed_id) {
var isOnMobile = (window.innerWidth <= 768);
// Hide menu level 3 ======================
if (!isOnMobile) {
var is_showing = true;
if (menuItem != null)
is_showing = (menuItem.querySelector('ul.children').style.display === "block");
if (is_showing) {
menuItem.querySelector('ul.children').style.display = "none";
return;
}
}
// Hide menu level 3 ======================
// Fix cho việc expand nội bộ từ level 3
var isInnerExpand = false;
if (isOnMobile)
isInnerExpand = true;
if (menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE'])
isInnerExpand = false;
var ulParent = menuItem.parentElement;
let ulChildrent = menuItem.querySelector('ul.children');
// Nếu trên mobile thì sẽ có 1 cái overlay màu xám
if (!(menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE']))
if (isInnerExpand) {
var liTitle = document.createElement("li");
liTitle.setAttribute("class", "overlay-container");
liTitle.innerHTML = '
';
ulParent.appendChild(liTitle);
}
if (ulChildrent.style.display == "none" || ulChildrent.style.display == "" || ulChildrent.style.display == "initial") {
hideAllLevel3Items();
if (menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE'])
displayElement(ulChildrent, true, "inline-block");
else
displayElement(ulChildrent, true, "block");
menuItem.classList.add("menu-expand");
menuItem.classList.add("menu-expand-level2");
} else {
hideAllLevel3Items();
menuItem.classList.remove("menu-expand");
menuItem.classList.remove("menu-expand-level2");
ulChildrent.style.display = "none";
}
if (isInnerExpand) {
/*
Phương án giải quyết: Tính một lần chiều cao của ulLength và lưu vào attribute.
*/
var ulLength = 0;
if (ulChildrent.getAttribute('ulLength'))
ulLength = ulChildrent.getAttribute('ulLength');
else {
ulLength = 8;
let liChildrent = ulChildrent.querySelectorAll("li.child");
for (i = 0; i < liChildrent.length; i++)
ulLength += liChildrent[i].offsetHeight;
ulChildrent.setAttribute('ulLength', ulLength);
}
// Expand menu height
menuItem.parentElement.style.height = ulLength + "px"; //(8 + ulChildrent.querySelector( 'li.child' ).offsetHeight * ulChildrent.querySelectorAll("li.child").length) + "px";
menuItem.parentElement.scrollTop = 0;
menuItem.parentElement.style.overflow = "hidden";
if (!isFromNotSkickyMenu(menuItem))
Helper.showNaviOverlay();
// 1. Cập nhật chiều cao của level 3 bằng level 2
ulChildrent.style.height = ulLength + "px";
/*
Phương án giải quyết: Nếu chưa fix chiều cao của ulChildrentTopFixed để sao cho top của level 3 bằng
top của level 2 thì tính toán và lưu vào attribute.
*/
if (ulChildrent.getAttribute('ulChildrentTopFixed'))
ulChildrentTopFixed = ulChildrent.getAttribute('ulChildrentTopFixed');
else {
// 2. Cập nhật top của level 3 bằng 0/level 2
ulChildrentTopFixed = ulChildrent.getBoundingClientRect().top - ulChildrent.parentElement.parentElement.getBoundingClientRect().top;
ulChildrent.setAttribute('ulChildrentTopFixed', ulChildrentTopFixed);
}
if (isNaviSection == true || isNaviSection == "true")
ulChildrentTopFixed = ulChildrentTopFixed - 10;
ulChildrent.style.top = (-ulChildrentTopFixed) + "px";
// 3. Đánh dấu là đã cập nhật rồi, ko cần update lại
ulChildrent.style.zIndex = 3;
// 4. Đôi khi ulChildrent.style.left cần update lại vì parent của nó có thể ở giữa màn hình.
if (isOnMobile) { // Việc này chỉ xảy ra trên mobile mà thôi.
ulChildrent.style.left = (48 - ulChildrent.parentElement.getBoundingClientRect().left) + "px";
}
}
}
var showLevel3Items_Desktop = function (menuItem, isNaviSection, menuKind, embed_id) {
var isOnMobile = (window.innerWidth <= 768);
var ulParent = menuItem.parentElement;
let ulChildrent = menuItem.querySelector('ul.children');
// Nếu trên desktop thì sẽ expand ra và set width con=bố
if (!isOnMobile) {
var setting = getSettingOfNaviman( embed_id );
/* Chỗ này chỉ đúng với mega menu thôi, còn bottom bar trên desktop thì cần sửa lại ****************************/
ulChildrent.parentElement.parentElement.style.overflow = "visible";
var submenuWidth = setting["submenuWidth"];
if (!(menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE']))
ulChildrent.style.width = submenuWidth + "px"; // ulChildrent.parentElement.parentElement.offsetWidth + "px";
// ở dưới
if (setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['BOTTOM_CENTER'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['BOTTOM_RIGHT'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['BOTTOM_LEFT'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['BOTTOM_FULL'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['TOP_FULL'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['BOTTOM_CENTER_FLOAT']) {
if (setting.subDirection == false || setting.subDirection == "false")
ulChildrent.style.left = "-" + ulChildrent.parentElement.parentElement.offsetWidth + "px";
else
ulChildrent.style.left = ulChildrent.parentElement.parentElement.offsetWidth + "px";
ulChildrent.style.overflow = "visible";
ulChildrent.style.height = "fit-content";
ulChildrent.style.top = "initial";
ulChildrent.style.bottom = "0px";
if (isNaviSection) {
ulChildrent.style.top = "0px";
ulChildrent.style.bottom = "initial";
}
}
// Nếu bottom bar nằm ở cạnh bên phải
if (setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_TOP'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_FULL_TOP'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['RIGHT_FULL_CENTER']) {
ulChildrent.style.left = "-" + ulChildrent.parentElement.parentElement.offsetWidth + "px";
}
// Nếu bottom bar nằm ở cạnh bên trái
if (setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_TOP'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_FULL_TOP'] || setting.desktopPosition == NAVIGLOBAL['DESKTOP_POSITION']['LEFT_FULL_CENTER']) {
ulChildrent.style.left = (ulChildrent.parentElement.parentElement.offsetWidth + 2) + "px";
}
/* Chỗ này sửa lại cho BOTTOM BAR trên desktop ***************************************************************/
Menu.Sticky.fixCSS_showLevel3Items_Desktop(menuItem, isNaviSection, menuKind, embed_id);
}
adjustMenuPosition(menuItem, menuKind, embed_id);
}
var backToLevel1 = function (event, item) {
// Hide all level 2
var level1Childrens = item.parentElement.parentElement.getElementsByClassName("children");
for (var i = 0; i < level1Childrens.length; i++) {
displayElement(level1Childrens[i], false);
}
var parrent = item.parentElement.parentElement;
parrent.style.height = "initial";
parrent.style.overflow = "auto";
// Remove overlay
var overlay = item.parentElement;
overlay.remove();
event.stopPropagation();
}
var isFromNotSkickyMenu = function (menuItem) {
var limitCount = 0;
while (true) {
limitCount++;
if (limitCount >= 30) return false;
if (menuItem.className.includes("section_naviman_app"))
return true;
if (menuItem == document.body)
return false;
menuItem = menuItem.parentElement;
}
}
var getSettingOfNaviman = function(embed_id) {
var navimanObj = null;
for (var i = 0; i < window.navimanData.length; i++)
if (window.navimanData[i]["embed_id"] == embed_id) {
navimanObj = window.navimanData[i];
break;
}
if( navimanObj == null ) {
console.log("Error: showLevel2Items - Can't find navimanObj");
return null;
}
return navimanObj["data"]["setting"];
}
// Hàm này sẽ truy ngược từ một menu item lên trên xem có chứa class publishToPlace ko
var isFrom_PublishToPlaceMenu = function (menuItem, embed_id ) {
let naviMenu = menuItem;
while (naviMenu && naviMenu.id !== embed_id && naviMenu.tagName !== "BODY") {
naviMenu = naviMenu.parentElement;
}
if (naviMenu && naviMenu.id === embed_id) {
return naviMenu.classList.contains("publishToPlace");
}
return false;
}
var saveOpeningMenuInfo = function(isShowing, menuItem, menuKind, embed_id) {
if (!isShowing) {
window._openingMenuItem = menuItem;
window._openingMenuKind = menuKind;
window._openingEmbedId = embed_id;
} else {
delete window._openingMenuItem;
delete window._openingMenuKind;
delete window._openingEmbedId;
}
}
let lastShowLevel2ItemsCall = 0;
var showLevel2Items = function (menuItem, menuKind, embed_id) {
Menu.Section.fixMobileMegamenuScrollPosition( menuItem );
var setting = getSettingOfNaviman( embed_id );
//********** Hàm kiểm tra để nếu dạng hover thì không bị giật giật do việc kiểm tra nếu hàm gọi quá nhanh và nhiều thì bỏ qua ******/
var desktopHover = isSettingBeTrue(setting['desktopHover']);
if( desktopHover ) {
let now = Date.now();
if (now - lastShowLevel2ItemsCall < 150) {
console.log("Reject showLevel2Items because called too fast:", now - lastShowLevel2ItemsCall, "ms");
return;
}
lastShowLevel2ItemsCall = now; // Cập nhật thời điểm gọi hàm
}
//**********************************************************************************************************************************/
// 1. Kiểm tra xem có những menu item nào đang được hiện không
var is_showing = true;
if (menuItem != null)
//is_showing = (menuItem.querySelector('ul.children').style.display === "block");
is_showing = ["block", "flex"].includes(menuItem.querySelector('ul.children').style.display);
// 2. Xoá sạch trạng thái hiện tại đi
var needCloseAllDropdowns = false;
// Giải thích: Nếu là các menu không phải hamburger thì cần reset tất cả các menu
if (!(menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE']))
needCloseAllDropdowns = true;
// Giải thích: Nếu là hamburger thì kiểm tra nếu mở rộng ra ngoài thì cũng cần reset tất cả các menu
if (menuKind == NAVIGLOBAL['MENU_KINDS']['CONTEXT_SLIDE']) {
if( window.hamburgerSubDirection[embed_id] == 2 )
needCloseAllDropdowns = true;
}
saveOpeningMenuInfo( is_showing, menuItem, menuKind, embed_id);
// 3. Kiểm tra nếu chưa hiện thì hiện các ông con
if (menuItem != null) {
if (!is_showing) {
Menu.Sticky.lockPageScrollingTabBar( menuKind, true );
if (needCloseAllDropdowns == true)
Helper.closeAllDropdowns();
/****************************************************
Logic là: Nếu như là full expand thì flex để tràn ra, còn lại thì block để hiện lên. */
if( menuItem.getAttribute('data-fullexpand') == "1" ) {
var ulChildrent = menuItem.querySelector('ul.children');
displayElement(ulChildrent, true, "flex");
// Kiểm tra nếu public ở dạng publishToPlace thì cần cập nhật lại vị trí
if( isFrom_PublishToPlaceMenu(menuItem, embed_id) )
maintainFullExpandDropdownPosition(ulChildrent, "PublishToPlace");
else
maintainFullExpandDropdownPosition(ulChildrent, "InsertToSection");
}
else
displayElement(menuItem.querySelector('ul.children'), true);
/****************************************************/
displayElement(menuItem.querySelector('span.arrow'), true);
menuItem.querySelector('ul.children').style.overflow = "auto";
menuItem.classList.add("menu-expand");
menuItem.classList.add("menu-expand-level1");
Menu.Common.setTopZindex(menuItem, menuKind, embed_id);
if (!isFromNotSkickyMenu(menuItem))
Helper.showNaviOverlay();
} else {
Menu.Sticky.lockPageScrollingTabBar( menuKind, false );
var closeDropDown = function () {
console.log("function: closeDropDown - Something wrong here ");
displayElement(menuItem.querySelector('ul.children'), false);
displayElement(menuItem.querySelector('span.arrow'), false);
menuItem.classList.remove("menu-expand");
menuItem.classList.remove("menu-expand-level1");
Menu.Common.removeTopZindex(menuItem, menuKind, embed_id);
Helper.hideNaviOverlay();
}
/****************************************************
* Đây là chỗ xử lý hover chuột ra ngoài menu item thì delay lại để ko tắt menu quá nhanh gây UX kém
*/
var isOnMobile = (window.innerWidth <= 768);
var isNeedDelay = false;
if( !isOnMobile )
if( desktopHover )
isNeedDelay = true;
if( isNeedDelay)
setTimeout(() => {
var menu = document.getElementById( embed_id );
if( !menu.matches(":hover") ) {
closeDropDown();
}
}, 300);
else // isNeedDelay == false
closeDropDown();
/****************************************************/
}
adjustMenuPosition(menuItem, menuKind, embed_id);
}
};
var adjustMenuPosition = function (menuItem, menuKind, embed_id) {
if (window.innerWidth < 769) return;
var menuChildren = menuItem.querySelector(":scope > ul");
if (!menuChildren) return;
var rect = menuChildren.getBoundingClientRect();
var viewportWidth = window.innerWidth;
if (rect.right > viewportWidth) {
var shift = viewportWidth - rect.right;
menuChildren.style.transform = `translateX(${shift}px)`;
} else if (rect.left < 0) {
var shift = -rect.left;
menuChildren.style.transform = `translateX(${shift}px)`;
}
};
var openNaviMenu = function(embedId) {
const element = document.querySelector("#" + embedId);
if (!element) return;
console.log("openNaviMenu:", embedId);
if (getComputedStyle(element).visibility !== "visible") {
// Mở menu ******************************<<<
const classList = element.classList;
Helper.showNaviOverlayGlobal();
element.style.visibility = "visible";
element.style.opacity = "0";
let transformFrom = null;
if (classList.contains("hamburger-left-right")) {
transformFrom = "translateX(-100%)";
} else if (classList.contains("hamburger-right-left")) {
transformFrom = "translateX(100%)";
} else if (classList.contains("hamburger-top-down")) {
transformFrom = "translateY(-100%)";
} else if (classList.contains("hamburger-down-top")) {
transformFrom = "translateY(100%)";
} else if (classList.contains("hamburger-fullscreen") || classList.contains("hamburger-fullpopup")) {
transformFrom = null; // Chỉ dùng opacity
} else {
// Không hiệu ứng nếu không khớp class nào
element.style.opacity = "1";
return;
}
if (transformFrom !== null) {
element.style.transform = transformFrom;
}
requestAnimationFrame(() => {
element.style.transition = "transform 0.3s ease-out, opacity 0.2s ease-out";
element.style.opacity = "1";
if (transformFrom !== null) {
element.style.transform = "translate(0, 0)";
}
// ⏳ Sau khi mở xong, xoá rác
setTimeout(() => {
["transform", "opacity", "transition"].forEach(prop => element.style.removeProperty(prop));
}, 300);
});
// Mở menu ******************************>>>
} else {
// Đóng menu
setTimeout(() => {
element.style.visibility = "hidden";
}, 300);
Helper.hideNaviOverlayGlobal();
}
callbackPublicFunc(openNaviMenu);
};
var openMobileMenu = function() {
const divMenu = document.querySelector('.header__icon--menu');
callbackPublicFunc_delay(openMobileMenu);
divMenu.addEventListener('click', () => {}); // Xem lai cho false nay
divMenu.click();
};
var openCart = function() {
const divMenu = document.querySelector('.header__icon--cart');
callbackPublicFunc_delay(openCart);
divMenu.addEventListener('click', () => {});
divMenu.click();
};
var openSearch = function() {
var isDawnFamily = true;
if(document.querySelector('details-modal.header__search') == null)
isDawnFamily = false;
if(document.querySelector('details-modal.header__search').querySelector("details") == null)
isDawnFamily = false;
callbackPublicFunc_delay(openSearch);
// Dawn & Craft
if( isDawnFamily ) {
const divMenuAll = document.querySelectorAll('details-modal.header__search details');
divMenuAll.forEach((divMenu) => {
// console.log(divMenu);
divMenu.setAttribute("open", "true");
divMenu.querySelector("input").focus();
});
}else {
const divMenu = document.querySelector('.header__icon--search');
divMenu.addEventListener('click', () => {});
divMenu.click();
}
};
var clickToElement = function ( cssClass ) {
console.log("clickToElement:", cssClass);
if( document.querySelector(cssClass) != null ) {
setTimeout(() => {
document.querySelector(cssClass).click();
return false;
}, "200");
}else
console.log("This theme is invalid. Can find: " + cssClass);
return false;
};
var focusToElement = function ( cssClass ) {
console.log("focusToElement:", cssClass);
if( document.querySelector(cssClass) != null ) {
setTimeout(() => {
document.querySelector(cssClass).focus();
return false;
}, "200");
}else
console.log("This theme is invalid. Can find: " + cssClass);
return false;
};
/***** Scroll to Up/OnPage ******************************************************************/
var scrollTop = function (topMargin = 0) {
callbackPublicFunc_delay(scrollTop);
window.scrollTo({ top: topMargin, behavior: "smooth" });
return false;
};
var scrollOnPage = function ( cssOrID ) {
var element = document.querySelector( cssOrID );
if( element != null )
element.scrollIntoView( {behavior: "smooth"});
callbackPublicFunc_delay(scrollOnPage);
};
var scrollBottom = function (bottomMargin = 0) {
callbackPublicFunc_delay(scrollBottom);
window.scrollTo({ top: (document.body.scrollHeight - screen.height - bottomMargin), behavior: "smooth" });
return false;
};
/***** Share/copy url ******************************************************************/
var shareCopyUrl = function () {
navigator.clipboard.writeText(window.location.href);
callbackPublicFunc_delay(shareCopyUrl);
return false;
};
var shareFacebook = function () {
var url = window.location.href;
callbackPublicFunc_delay(shareFacebook);
window.open('https://www.facebook.com/sharer/sharer.php?u=' + url, '_blank');
return false;
};
var shareTweet = function () {
var url = window.location.href;
callbackPublicFunc_delay(shareTweet);
window.open('https://twitter.com/share?url=' + url, '_blank');
return false;
};
/***** Theme: Tailor https://themes.shopify.com/themes/tailor/styles/cotton ******************/
var openMenu_Tailor = function() {
callbackPublicFunc_delay(openMenu_Tailor);
return clickToElement('.header__controls .header__menu-button');
};
var openSearch_Tailor = function() {
callbackPublicFunc_delay(openSearch_Tailor);
return clickToElement('.header__controls .header__search-button');
};
var openCart_Tailor = function() {
callbackPublicFunc_delay(openCart_Tailor);
return clickToElement('.header__controls .header__cart-button');
};
/***** Theme: Symmetry https://themes.shopify.com/themes/symmetry/styles/beatnik ******************/
var openMenu_Symmetry = function() {
callbackPublicFunc_delay(openMenu_Symmetry);
return clickToElement(".mobile-nav-toggle");
};
var openSearch_Symmetry = function() {
callbackPublicFunc_delay(openSearch_Symmetry);
return clickToElement(".show-search-link");
};
var openCart_Symmetry = function() {
callbackPublicFunc_delay(openCart_Symmetry);
return clickToElement(".cart-link");
};
/***** Theme: Pipeline https://themes.shopify.com/themes/pipeline/styles/bright ******************/
var openMenu_Pipeline = function() {
callbackPublicFunc_delay(openMenu_Pipeline);
return clickToElement('[data-drawer-toggle="hamburger"]');
};
var openCart_Pipeline = function() {
callbackPublicFunc_delay(openCart_Pipeline);
return clickToElement('[data-drawer-toggle="drawer-cart"]');
};
var openSearch_Pipeline = function() {
openMenu_Pipeline();
setTimeout(() => {
focusToElement('[type="search"]');
}, "300");
callbackPublicFunc_delay(openSearch_Pipeline);
return;
};
/***** Theme: Empire https://themes.shopify.com/themes/empire/styles/supply ******************/
var openMenu_Empire = function() {
callbackPublicFunc_delay(openMenu_Empire);
return clickToElement('.site-header-menu-toggle--button');
};
var openSearch_Empire = function() {
callbackPublicFunc_delay(openSearch_Empire);
return clickToElement('.site-header-mobile-search-button--button');
};
/***** Theme: Impulse https://themes.shopify.com/themes/impulse/styles/modern ******************/
var openMenu_Impulse = function() {
if(!document.documentElement.classList.contains("js-drawer-open")) {
setTimeout(() => {
document.querySelector('.js-drawer-open-nav').click();
}, "200");
callbackPublicFunc_delay(openMenu_Impulse);
}
return false;
};
var openSearch_Impulse = function() {
callbackPublicFunc_delay(openSearch_Impulse);
return clickToElement('.js-search-header');
};
var openCart_Impulse = function() {
if(!document.documentElement.classList.contains("js-drawer-open")) {
setTimeout(() => {
document.querySelector('.js-drawer-open-cart').click();
}, "200");
callbackPublicFunc_delay(openCart_Impulse);
}
return false;
};
/***** Theme: Enterprise https://themes.shopify.com/themes/enterprise/styles/active ******************/
var openMenu_Enterprise = function() {
callbackPublicFunc_delay(openMenu_Enterprise);
return clickToElement('.main-menu__toggle');
};
var openCart_Enterprise = function() {
callbackPublicFunc_delay(openCart_Enterprise);
return clickToElement('#cart-icon');
};
/***** Theme: Warehouse https://themes.shopify.com/themes/warehouse/styles/metal ******************/
var openMenu_Warehouse = function() {
callbackPublicFunc_delay(openMenu_Warehouse);
return clickToElement('[data-action="toggle-menu"]');
};
var openCart_Warehouse = function() {
callbackPublicFunc_delay(openCart_Warehouse);
return clickToElement('[data-action="toggle-mini-cart"]');
};
var openSearch_Warehouse = function() {
callbackPublicFunc_delay(openSearch_Warehouse);
return clickToElement('[data-action="toggle-search"]');
};
/***** Theme: Hongo https://preview.themeforest.net/item/hongo-multipurpose-shopify-theme-os-20 ******************/
var openMenu_Hongo = function() {
callbackPublicFunc_delay(openMenu_Hongo);
return clickToElement('.navbar .navbar-toggler');
};
var openCart_Hongo = function() {
callbackPublicFunc_delay(openCart_Hongo);
return clickToElement('.navbar [aria-label="cart"]');
};
var openSearch_Hongo = function() {
callbackPublicFunc_delay(openSearch_Hongo);
return clickToElement('.navbar .search');
};
/***** Theme: Shark https://themes.shopify.com/themes/shark/styles/bright ******************/
var openMenu_Shark = function() {
callbackPublicFunc_delay(openMenu_Shark);
return clickToElement('.hamburger-toggler');
};
var openCart_Shark = function() {
callbackPublicFunc_delay(openCart_Shark);
return clickToElement('.cart .header-icons-link');
};
var openSearch_Shark = function() {
callbackPublicFunc_delay(openSearch_Shark);
return clickToElement('.search .header-icons-link');
};
/***** Theme: District https://themes.shopify.com/themes/district/styles/district ******************/
var openMenu_District = function() {
callbackPublicFunc_delay(openMenu_District);
return clickToElement('.header-top__menu');
};
var openCart_District = function() {
callbackPublicFunc_delay(openCart_District);
return clickToElement('.header-top__cart-button');
};
var openSearch_District = function() {
callbackPublicFunc_delay(openSearch_District);
if (document.querySelector('.header-top__search')) {
return clickToElement('.header-top__search');
} else {
clickToElement('.header-top__menu');
setTimeout(function() {
clickToElement("#menu.panel .search");
}, 1000);
}
};
/***** Theme: Honey https://themes.shopify.com/themes/honey/styles/paws ******************/
var openMenu_Honey = function() {
callbackPublicFunc_delay(openMenu_Honey);
return clickToElement('.header__icon--menu');
};
var openCart_Honey = function() {
callbackPublicFunc_delay(openCart_Honey);
return clickToElement('.header__icon--cart');
};
var openSearch_Honey = function() {
if (document.getElementById("search-home-field")) {
window.scrollTo({ top: 0, behavior: "smooth" });
setTimeout(() => {
naviman.focusToElement('#Search-In-Template');
// Add animation
document.getElementById("Search-In-Template").classList.add('animate__animated', 'animate__flash');
// Remove animation
setTimeout(() => {
document.getElementById("Search-In-Template").classList.remove('animate__animated', 'animate__flash');
}, 1000);
}, 1000);
} else {
window.scrollTo({ top: 0, behavior: "smooth" });
setTimeout(() => {
naviman.clickToElement('[aria-label="Search"]');
}, 500);
}
return true;
};
/***** Theme: Focal https://themes.shopify.com/themes/focal/styles/carbon ******************/
var openMenu_Focal = function() {
callbackPublicFunc_delay(openMenu_Focal);
return clickToElement('[aria-controls="mobile-menu-drawer"]');
};
var openCart_Focal = function() {
callbackPublicFunc_delay(openCart_Focal);
return clickToElement('[aria-controls="mini-cart"]');
};
var openSearch_Focal = function() {
callbackPublicFunc_delay(openSearch_Focal);
return clickToElement('[aria-controls="search-drawer"]');
};
/***** Theme: Xclusive https://themes.shopify.com/themes/xclusive/styles/shoes ******************/
var openMenu_Xclusive = function() {
callbackPublicFunc_delay(openMenu_Xclusive);
return clickToElement('[aria-controls="nav"]');
};
var openCart_Xclusive = function() {
callbackPublicFunc_delay(openCart_Xclusive);
return clickToElement('[aria-controls="cart"]');
};
var openSearch_Xclusive = function() {
callbackPublicFunc_delay(openSearch_Xclusive);
return clickToElement('.search-compact');
};
/***** Theme: Prestige https://themes.shopify.com/themes/prestige/styles/couture ******************/
var openMenu_Prestige = function() {
callbackPublicFunc_delay(openMenu_Prestige);
return clickToElement('[aria-controls="sidebar-menu"]');
};
var openCart_Prestige = function() {
callbackPublicFunc_delay(openCart_Prestige);
return clickToElement('[aria-controls="cart-drawer"]');
};
var openSearch_Prestige = function() {
callbackPublicFunc_delay(openSearch_Prestige);
return clickToElement('.header__search-link a');
};
/***** Theme: Palo Alto https://themes.shopify.com/themes/palo-alto/styles/vibrant ******************/
var openMenu_PaloAlto = function() {
callbackPublicFunc_delay(openMenu_PaloAlto);
return clickToElement('[aria-controls="nav-drawer"]');
};
var openCart_PaloAlto = function() {
callbackPublicFunc_delay(openCart_PaloAlto);
return clickToElement('[aria-controls="cart-drawer"]');
};
var openSearch_PaloAlto = function() {
callbackPublicFunc_delay(openSearch_PaloAlto);
return clickToElement('.mobile-menu .search-popdown__toggle');
};
/***** Theme: Minion https://themes.shopify.com/themes/minion/styles/vertical ******************/
var openMenu_Minion = function() {
callbackPublicFunc_delay(openMenu_Minion);
return clickToElement(".drawer__icon-menu");
};
var openCart_Minion = function() {
callbackPublicFunc_delay(openCart_Minion);
return clickToElement("#cart-icon-bubble--mobile");
};
var openSearch_Minion = function() {
callbackPublicFunc_delay(openSearch_Minion);
window.scrollTo({ top: 0, behavior: "smooth" });
return focusToElement("#Search-In-Modal-mobile");
};
/***** Theme: Borders https://themes.shopify.com/themes/borders/styles/raw ******************/
var openMenu_Borders = function() {
callbackPublicFunc_delay(openMenu_Borders);
return clickToElement( ".mobile-menu-button" );
};
var openCart_Borders = function() {
callbackPublicFunc_delay(openCart_Borders);
return clickToElement('[aria-controls="site-cart-sidebar"]');
};
var openSearch_Borders = function() {
callbackPublicFunc_delay(openSearch_Borders);
return clickToElement('[aria-controls="site-search-sidebar"]');
};
/***** Theme: Impact https://themes.shopify.com/themes/impact/styles/sound ******************/
var openMenu_Impact = function() {
callbackPublicFunc_delay(openMenu_Impact);
clickToElement('[aria-controls="header-sidebar-menu"]');
};
var openCart_Impact = function() {
callbackPublicFunc_delay(openCart_Impact);
clickToElement('[aria-controls="cart-drawer"]');
};
var openSearch_Impact = function() {
callbackPublicFunc_delay(openSearch_Impact);
clickToElement('[aria-controls="search-drawer"]');
};
/***** Theme: Broadcast https://themes.shopify.com/themes/broadcast/styles/clean ******************/
var openMenu_Broadcast = function() {
callbackPublicFunc_delay(openMenu_Broadcast);
return clickToElement('.header__mobile__hamburger');
};
var openCart_Broadcast = function() {
callbackPublicFunc_delay(openCart_Broadcast);
return clickToElement('.navlink--cart');
};
var openSearch_Broadcast = function() {
callbackPublicFunc_delay(openSearch_Broadcast);
return clickToElement('.navlink--search');
};
/***** Theme: Expanse https://themes.shopify.com/themes/expanse/styles/classic ******************/
var openMenu_Expanse = function() {
callbackPublicFunc_delay(openMenu_Expanse);
return clickToElement('.mobile-nav-trigger');
};
var openCart_Expanse = function() {
callbackPublicFunc_delay(openCart_Expanse);
return clickToElement('#HeaderCartTrigger');
};
var openSearch_Expanse = function() {
callbackPublicFunc_delay(openSearch_Expanse);
return clickToElement('.js-search-header');
};
/***** Theme: ShowTime https://themes.shopify.com/themes/showtime/styles/cooktime ******************/
var openMenu_ShowTime = function() {
callbackPublicFunc_delay(openMenu_ShowTime);
return clickToElement('[class="#main-navigation-mobile-icon"]');
};
var openCart_ShowTime = function() {
callbackPublicFunc_delay(openCart_ShowTime);
return clickToElement('cart-drawer-trigger');
};
var openSearch_ShowTime = function() {
callbackPublicFunc_delay(openSearch_ShowTime);
var input = document.querySelector('[class="#header-searchbar-input"]');
input.addEventListener('touchstart', function() { input.focus(); });
input.addEventListener('click', function() { input.focus(); });
setTimeout(() => {
input.focus();
}, 500);
};
/***** Theme: Local https://themes.shopify.com/themes/local/styles/light ******************/
var openMenu_Local = function() {
callbackPublicFunc_delay(openMenu_Local);
return clickToElement('.mobile-menu-button');
};
var openCart_Local = function() {
callbackPublicFunc_delay(openCart_Local);
return focusToElement('.mobile-search input');
};
var openSearch_Local = function() {
callbackPublicFunc_delay(openSearch_Local);
return clickToElement('.mobile-cart-button');
};
/***** Theme: Avenue https://themes.shopify.com/themes/avenue/styles/casual ******************/
var openMenu_Avenue = function() {
callbackPublicFunc_delay(openMenu_Avenue);
return clickToElement('.toggleMenu');
};
var openCart_Avenue = function() {
callbackPublicFunc_delay(openCart_Avenue);
return clickToElement('#cart-count-mobile .cart-count-mobile');
};
/*var openSearch_Avenue = function() {
return clickToElement('.mobile-cart-button');
};*/
/***** Theme: Parallax https://themes.shopify.com/themes/parallax/styles/aspen ******************/
var openMenu_Parallax = function() {
callbackPublicFunc_delay(openMenu_Parallax);
return clickToElement('.icon-menu');
};
var openCart_Parallax = function() {
callbackPublicFunc_delay(openCart_Parallax);
return clickToElement('.icon-cart');
};
var openSearch_Parallax = function() {
window.scrollTo({ top: 0, behavior: "smooth" });
var input = document.querySelector('.mobile-search-bar .search-form__input');
input.addEventListener('touchstart', function() { input.focus(); });
input.addEventListener('click', function() { input.focus(); });
setTimeout(() => {
input.focus(); // Focus vào textbox sau khi sự kiện đã được xử lý
}, 500);
callbackPublicFunc(openSearch_Parallax);
return false;
};
/******************************************************************************************/
var callPublicFunction = function (functionName, context /*, args */) {
var args = Array.prototype.slice.call(arguments, 2);
var namespaces = functionName.split(".");
var func = namespaces.pop();
for(var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
if(typeof context[func] === "function") {
return context[func].apply(context, args);
} else {
//console.log("Function not found: " + functionName);
}
}
var scrollToHide = function (screen, cssNaviPrefix) {
var isOnMobile = window.innerWidth <= 768;
cssNaviPrefix = cssNaviPrefix.trim();
let autoHide = false;
if (screen == "mobile") {
if (isOnMobile)
autoHide = true;
} else {
if (!isOnMobile)
autoHide = true;
}
let obj = document.getElementsByClassName(cssNaviPrefix.substr(1) )[0]; // SF-1234567890
if (autoHide) {
window.addEventListener('scroll',
function (e) {
var scrollTop = document.documentElement.scrollTop;
if (scrollTop > SCROLL_TO_HIDE) {
if( obj.style.display != 'none' ) {
obj.style.display = 'none';
callPublicFunction("naviApp_scrollToHide_Hide", this);
callbackPublicFunc(scrollToHide);
}
} else {
if( obj.style.display != 'block' ) {
obj.style.display = 'block';
callPublicFunction("naviApp_scrollToHide_Show", this);
callbackPublicFunc(scrollToHide);
}
}
});
}
};
var scrollToShow = function (screen, cssNaviPrefix) {
if( naviman_version == "simulator" )
return;
var isOnMobile = window.innerWidth <= 768;
if ((isOnMobile && screen === "desktop") || (!isOnMobile && screen === "mobile")) return;
cssNaviPrefix = cssNaviPrefix.trim();
let autoShow = false;
if (screen == "mobile") {
if (isOnMobile)
autoShow = true;
} else {
if (!isOnMobile)
autoShow = true;
}
let obj = document.getElementsByClassName(cssNaviPrefix.substr(1))[0];
if (!obj) return;
console.log("scrollToShow " + screen + ": ", cssNaviPrefix);
if (autoShow) {
obj.style.display = 'none'; // mặc định ẩn
window.addEventListener('scroll', function () {
var scrollTop = document.documentElement.scrollTop;
if (scrollTop > SCROLL_TO_SHOW) {
if (obj.style.display !== 'block') {
obj.style.display = 'block';
callPublicFunction("naviApp_scrollToShow_Show", this);
callbackPublicFunc(scrollToShow);
}
} else {
if (obj.style.display !== 'none') {
obj.style.display = 'none';
callPublicFunction("naviApp_scrollToShow_Hide", this);
callbackPublicFunc(scrollToShow);
}
}
});
}
};
var openInbox_loopHideChat = function () {
var isLoop = true;
//console.log("loopHideChat");
if( document.querySelector('#ShopifyChat').getAttribute("is-open") == "false" )
if( document.querySelector('#ShopifyChat').style.visibility == "visible" ) {
document.querySelector('#ShopifyChat').style.visibility = "hidden";
isLoop = false;
}
callbackPublicFunc(openInbox_loopHideChat);
if( isLoop ) {
setTimeout(function () {
openInbox_loopHideChat();
}, 200);
}
};
var openInbox_loopHideFAB = function () {
var isLoop = true;
if (document.querySelector('#ShopifyChat') != null) {
document.querySelector('#ShopifyChat').style.visibility = "hidden";
isLoop = false;
}
if (isLoop) {
setTimeout(function () {
openInbox_loopHideFAB();
}, 200);
}
};
var openInbox = function() {
if( document.querySelector('#ShopifyChat') == null ) {
console.log("Navi+: Shopify inbox is not installed. Read document
here");
}
var divMenu = document.querySelector('#ShopifyChat').shadowRoot.querySelector('.chat-toggle');
document.querySelector('#ShopifyChat').style.visibility = "visible";
divMenu.addEventListener('click', () => {});
divMenu.click();
callbackPublicFunc(openInbox);
setTimeout(function() {
openInbox_loopHideChat();
}, 200);
};
var openInboxWithoutReplace = function() {
if( document.querySelector('#ShopifyChat') == null ) {
console.log("Navi+: Shopify inbox is not installed. Read document
here");
}
var divMenu = document.querySelector('#ShopifyChat').shadowRoot.querySelector('.chat-toggle');
document.querySelector('#ShopifyChat').style.visibility = "visible";
divMenu.addEventListener('click', () => {});
divMenu.click();
callbackPublicFunc(openInboxWithoutReplace);
};
var openShareMe = function(){
if (navigator.share) {
navigator.share({
title: document.title,
text: "Navi+ share",
url: window.location.href
})
.then(() => console.log('Successful share'))
.catch(error => console.log('Error sharing:', error));
}else
console.log("This device does not support share directly!");
callbackPublicFunc(openShareMe);
}
var callbackPublicFunc = function(func, embedID = "") {
let callbackName = `Navi.${func.name}_Callback`;
if (window.Navi)
{
if (typeof eval(callbackName) === 'function') {
eval(callbackName + '("'+ embedID +'")' );
console.log('Executed: '+ `${callbackName}` + '("'+ embedID +'") ');
} else {
// console.log(`${callbackName} is not found!`);
}
}else
console.log(`The function ${callbackName} is not defined.`);
}
var callbackPublicFunc_delay = function(func, embedID = "") {
setTimeout(() => { callbackPublicFunc(func, embedID); }, 500);
}
function goBack() {
window.history.back();
}
function goForward() {
window.history.forward();
} var asyncGetCart = async function() {
const result = await fetch(window.Shopify.routes.root + 'cart.json');
if (result.status === 200) {
return result.json();
}
throw new Error(`Failed to get request, Shopify returned ${result.status} ${result.statusText}`);
};
var updateCartCount = function( item_count ) {
// Todo 19/6: Chỗ này cần test kỹ càng, ko work rồi vì nếu trộn lẫn thì sẽ ko chạy
var isHideBadge = false;
var span = document.querySelectorAll('li.item_badge_withcount span.cart_count');
for (var i = 0; i < span.length; i++) {
span[i].textContent = item_count;
if( item_count == 0 ) {
span[i].style.display = "none";
isHideBadge = true;
}
else
span[i].style.display = "initial";
}
var span = document.querySelectorAll('li.child_badge_withcount span.cart_count');
for (var i = 0; i < span.length; i++) {
span[i].textContent = item_count;
if( item_count == 0 ) {
span[i].style.display = "none";
isHideBadge = true;
}
else
span[i].style.display = "initial";
}
if( item_count == 0 ) {
document.documentElement.style.setProperty('--cart-count-number', '');
}else {
document.documentElement.style.setProperty('--cart-count-number', `"${item_count}"`);
}
const root = document.querySelector(":root");
if( isHideBadge )
root.style.setProperty("--cart-count-text", '""');
else
root.style.setProperty("--cart-count-text", '"●"');
callbackPublicFunc(updateCartCount);
};
var checkAndUpdateCartCount = function() {
asyncGetCart().then( function(result) {
updateCartCount(result.item_count);
});
};
var setCartCount = function(count)
{
cartCount = count;
};
/*window.addEventListener('SCE:mutate', (event) => {
updateCartCount();
});*/
/** Library for cart event listener ********************/
(function () {
if (!window || !window.Shopify) return;
const CartEvents = {
add: "SCE:add",
update: "SCE:update",
change: "SCE:change",
clear: "SCE:clear",
mutate: "SCE:mutate",
};
const ShopifyCartURLs = [
"/cart/add",
"/cart/update",
"/cart/change",
"/cart/clear",
"/cart/add.js",
"/cart/update.js",
"/cart/change.js",
"/cart/clear.js",
];
function isShopifyCartURL(url) {
if (!url) return false;
if (typeof url === 'string' || url instanceof String) {
const path = url.split("/").pop();
return ShopifyCartURLs.includes(`/cart/${path}`);
}
return false;
}
function updateType(url) {
if (!url) return false;
if (url.includes("cart/add")) {
return "add";
} else if (url.includes("cart/update")) {
return "update";
} else if (url.includes("cart/change")) {
return "change";
} else if (url.includes("cart/clear")) {
return "clear";
} else return false;
}
function dispatchEvent(url, detail) {
if (typeof detail === "string") {
try {
detail = JSON.parse(detail);
console.log( detail );
} catch (err) {
}
}
window.dispatchEvent(new CustomEvent(CartEvents.mutate, { detail }));
const type = updateType(url);
switch (type) {
case "add":
window.dispatchEvent(new CustomEvent(CartEvents.add, { detail }));
break;
case "update":
window.dispatchEvent(new CustomEvent(CartEvents.update, { detail }));
break;
case "change":
window.dispatchEvent(new CustomEvent(CartEvents.change, { detail }));
break;
case "clear":
window.dispatchEvent(new CustomEvent(CartEvents.clear, { detail }));
break;
default:
break;
}
}
function XHROverride() {
if (!window.XMLHttpRequest) return;
const originalOpen = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function () {
const url = arguments[1];
this.addEventListener("load", function () {
if (isShopifyCartURL(url)) {
dispatchEvent(url, this.response);
}
});
return originalOpen.apply(this, arguments);
};
}
function fetchOverride() {
if (!window.fetch || typeof window.fetch !== "function") return;
const originalFetch = window.fetch;
window.fetch = function () {
const response = originalFetch.apply(this, arguments);
//console.log(arguments);
if (isShopifyCartURL(arguments[0])) {
response.then((res) => {
res
.clone()
.json()
.then((data) => dispatchEvent(res.url, data));
});
}
return response;
};
}
fetchOverride();
XHROverride();
})();
/******** LOCAL STORAGE ******************************/
function setLocalStorage(key, value, ttl = 15000) {
if( !naviman.isLocalStorageSupported() )
return null;
const now = new Date()
// `item` is an object which contains the original value
// as well as the time when it's supposed to expire
const item = {
value: value,
expiry: now.getTime() + ttl,
}
localStorage.setItem(key, JSON.stringify(item))
}
function getLocalStorage(key) {
if( !naviman.isLocalStorageSupported() )
return null;
const itemStr = localStorage.getItem(key)
// if the item doesn't exist, return null
if (!itemStr) {
return null
}
const item = JSON.parse(itemStr)
const now = new Date()
// compare the expiry time of the item with the current time
if (now.getTime() > item.expiry) {
// If the item is expired, delete the item from storage
// and return null
localStorage.removeItem(key)
return null
}
return item.value
}
function turnOffLocalStorage() {
// Kiểm tra nếu hàm đã được gọi trước đó
if (window._localStorageDisabled) {
console.log("LocalStorage has already been disabled.");
return;
}
console.log("----- TURN OFF: LOCALSTORAGE ------");
// Ghi đè thuộc tính localStorage
Object.defineProperty(window, 'localStorage', {
get() {
console.error('LocalStorage is disabled.');
}
});
// Đặt cờ để ngăn việc gọi lại
window._localStorageDisabled = true;
}
function isLocalStorageSupported() {
// Nếu kết quả đã được lưu, trả về ngay
if (typeof window._localStorageSupport !== 'undefined') {
return window._localStorageSupport;
}
// Kiểm tra hỗ trợ localStorage
try {
const testKey = '__test__';
localStorage.setItem(testKey, 'test');
localStorage.removeItem(testKey);
window._localStorageSupport = true; // Lưu kết quả vào window
} catch (e) {
window._localStorageSupport = false; // Lưu kết quả vào window
}
return window._localStorageSupport;
}
/******** SESSION STORAGE ******************************/
function setSessionStorage(key, value) {
if (!naviman.isSessionStorageSupported()) {
return null;
}
// Lưu dữ liệu dưới dạng chuỗi JSON
const item = { value: value };
sessionStorage.setItem(key, JSON.stringify(item));
}
function getSessionStorage(key) {
if (!naviman.isSessionStorageSupported()) {
return null;
}
const itemStr = sessionStorage.getItem(key);
// Nếu không tìm thấy, trả về null
if (!itemStr) {
return null;
}
// Parse dữ liệu JSON và trả về giá trị gốc
const item = JSON.parse(itemStr);
return item.value !== undefined ? item.value : null;
}
function isSessionStorageSupported() {
// Nếu kết quả đã được lưu, trả về ngay
if (typeof window._sessionStorageSupport !== 'undefined') {
return window._sessionStorageSupport;
}
// Kiểm tra hỗ trợ sessionStorage
try {
const testKey = '__test__';
sessionStorage.setItem(testKey, 'test');
sessionStorage.removeItem(testKey);
window._sessionStorageSupport = true; // Lưu kết quả vào window
} catch (e) {
window._sessionStorageSupport = false; // Lưu kết quả vào window
}
return window._sessionStorageSupport;
}
return {
Name: "Naviman Libraries",
drawBottomNav: drawBottomNav,
init: init,
gotoUrl: gotoUrl,
backToLevel1: backToLevel1,
clickToElement: clickToElement,
focusToElement: focusToElement,
// Trigger
openNaviMenu: openNaviMenu,
// public JS functions
openMobileMenu: openMobileMenu,
openCart: openCart,
openSearch: openSearch,
// Scroll
scrollTop:scrollTop,
scrollBottom:scrollBottom,
scrollOnPage:scrollOnPage,
// Share
shareCopyUrl:shareCopyUrl,
shareFacebook:shareFacebook,
shareTweet:shareTweet,
// Tailor - https://themes.shopify.com/themes/tailor/styles/cotton
openMenu_Tailor: openMenu_Tailor,
openSearch_Tailor: openSearch_Tailor,
openCart_Tailor: openCart_Tailor,
// Symmetry - https://themes.shopify.com/themes/symmetry/styles/beatnik
openMenu_Symmetry: openMenu_Symmetry,
openSearch_Symmetry: openSearch_Symmetry,
openCart_Symmetry: openCart_Symmetry,
// Enterprise - https://themes.shopify.com/themes/tailor/styles/cotton
openMenu_Enterprise: openMenu_Enterprise,
openCart_Enterprise: openCart_Enterprise,
// Pipeline https://themes.shopify.com/themes/pipeline/styles/bright
openMenu_Pipeline: openMenu_Pipeline,
openSearch_Pipeline: openSearch_Pipeline,
openCart_Pipeline: openCart_Pipeline,
// Empire - https://themes.shopify.com/themes/empire/styles/supply
openMenu_Empire: openMenu_Empire,
openSearch_Empire: openSearch_Empire,
// Impulse - https://themes.shopify.com/themes/impulse/styles/modern
openMenu_Impulse: openMenu_Impulse,
openSearch_Impulse: openSearch_Impulse,
openCart_Impulse: openCart_Impulse,
// Warehouse - https://themes.shopify.com/themes/impact/styles/sound
openMenu_Warehouse: openMenu_Warehouse,
openCart_Warehouse: openCart_Warehouse,
openSearch_Warehouse: openSearch_Warehouse,
// Hongo - https://preview.themeforest.net/item/hongo-multipurpose-shopify-theme-os-20
openMenu_Hongo: openMenu_Hongo,
openCart_Hongo: openCart_Hongo,
openSearch_Hongo: openSearch_Hongo,
// Shark - https://themes.shopify.com/themes/shark/styles/bright
openMenu_Shark: openMenu_Shark,
openCart_Shark: openCart_Shark,
openSearch_Shark: openSearch_Shark,
// District - https://themes.shopify.com/themes/district/styles/district
openMenu_District: openMenu_District,
openCart_District: openCart_District,
openSearch_District: openSearch_District,
// Honey - https://themes.shopify.com/themes/honey/styles/paws
openMenu_Honey: openMenu_Honey,
openCart_Honey: openCart_Honey,
openSearch_Honey: openSearch_Honey,
// Focal - https://themes.shopify.com/themes/focal/styles/carbon
openMenu_Focal: openMenu_Focal,
openCart_Focal: openCart_Focal,
openSearch_Focal: openSearch_Focal,
// Xclusive - https://themes.shopify.com/themes/xclusive/styles/shoes
openMenu_Xclusive: openMenu_Xclusive,
openCart_Xclusive: openCart_Xclusive,
openSearch_Xclusive: openSearch_Xclusive,
// Prestige - https://themes.shopify.com/themes/prestige/styles/couture
openMenu_Prestige: openMenu_Prestige,
openCart_Prestige: openCart_Prestige,
openSearch_Prestige: openSearch_Prestige,
// Palo Alto https://themes.shopify.com/themes/palo-alto/styles/vibrant
openMenu_PaloAlto: openMenu_PaloAlto,
openCart_PaloAlto: openCart_PaloAlto,
openSearch_PaloAlto: openSearch_PaloAlto,
// Minion https://themes.shopify.com/themes/minion/styles/vertical
openMenu_Minion: openMenu_Minion,
openCart_Minion: openCart_Minion,
openSearch_Minion: openSearch_Minion,
// Borders https://themes.shopify.com/themes/borders/styles/raw
openMenu_Borders: openMenu_Borders,
openCart_Borders: openCart_Borders,
openSearch_Borders: openSearch_Borders,
// Impact - https://themes.shopify.com/themes/Impact/styles/metal
openMenu_Impact: openMenu_Impact,
openCart_Impact: openCart_Impact,
openSearch_Impact: openSearch_Impact,
// Broadcast - https://themes.shopify.com/themes/broadcast/styles/clean
openMenu_Broadcast: openMenu_Broadcast,
openCart_Broadcast: openCart_Broadcast,
openSearch_Broadcast: openSearch_Broadcast,
// Expanse - https://themes.shopify.com/themes/expanse/styles/classic
openMenu_Expanse: openMenu_Expanse,
openCart_Expanse: openCart_Expanse,
openSearch_Expanse: openSearch_Expanse,
// ShowTime - https://themes.shopify.com/themes/showtime/styles/cooktime
openMenu_ShowTime: openMenu_ShowTime,
openCart_ShowTime: openCart_ShowTime,
openSearch_ShowTime: openSearch_ShowTime,
// Local - https://themes.shopify.com/themes/local/styles/light
openMenu_Local: openMenu_Local,
openCart_Local: openCart_Local,
openSearch_Local: openSearch_Local,
// Avenue - https://themes.shopify.com/themes/avenue/styles/casual
openMenu_Avenue: openMenu_Avenue,
openCart_Avenue: openCart_Avenue,
// openSearch_Avenue: openSearch_Avenue,
// Parallax - https://themes.shopify.com/themes/parallax/styles/aspen
openMenu_Parallax: openMenu_Parallax,
openCart_Parallax: openCart_Parallax,
openSearch_Parallax: openSearch_Parallax,
// Work with other applications
openInbox: openInbox,
openInboxWithoutReplace: openInboxWithoutReplace,
openShareMe: openShareMe,
isHadValue: isHadValue, // TODO: No need publish this function
goBack: goBack,
goForward: goForward,
// Cart
setCartCount: setCartCount,
asyncGetCart:asyncGetCart,
checkAndUpdateCartCount:checkAndUpdateCartCount,
updateCartCount:updateCartCount,
generateActiveItems:generateActiveItems,
isMobileMode: isMobileMode,
setLocalStorage: setLocalStorage,
getLocalStorage: getLocalStorage,
isLocalStorageSupported: isLocalStorageSupported,
setSessionStorage: setSessionStorage,
getSessionStorage: getSessionStorage,
isSessionStorageSupported: isSessionStorageSupported,
callbackPublicFunc: callbackPublicFunc,
turnOffLocalStorage: turnOffLocalStorage,
openDebugMode: openDebugMode,
closeDebugMode: closeDebugMode,
debugModeLog: debugModeLog,
showLevel2Items: showLevel2Items,
Helper: Helper
};
})();
var Navi = Navi || {};
/** uigen/fix_by_cases.js ****************************************/
/*
Fix cho trường hợp click ra ngoài thì đóng toàn bộ menu, quay về trạng thái ban đầu mặc định
*/
if (!window._navimanClickListenerAttached) {
window._navimanClickListenerAttached = true;
/*******************************************************
* Fix cho việc hover chuột qua thì hiện lên luôn trên desktop.
********************************************************/
window.addEventListener("load", function() {
if (!naviman.isMobileMode()) {
setTimeout(() => {
var actions = document.getElementsByClassName("navi-hover");
for (var i = 0; i < actions.length; i++) {
actions[i].addEventListener("mouseover", function () {
if (!this.classList.contains("navi-hover-active")) {
this.classList.add("navi-hover-active");
this.click();
}
});
actions[i].addEventListener("mouseout", function () {
if (this.classList.contains("navi-hover-active")) {
this.classList.remove("navi-hover-active");
this.click();
}
});
}
}, 1000);
}
}); // Load xong file mới add các hàm này vào.
/*******************************************************
Kiểm tra và giữ lại chỉ một phần tử navigation trong mỗi naviItem
*******************************************************/
window.addEventListener("load", function() {
const naviItems = document.querySelectorAll('.naviItem');
naviItems.forEach(item => {
const navigations = item.querySelectorAll('ul.navigation');
if (navigations.length > 1) {
// Giữ lại phần tử đầu tiên, xoá các phần tử còn lại
for (let i = 1; i < navigations.length; i++) {
navigations[i].remove();
}
}
});
});
/*******************************************************
Fix cho việc bấm vào ngoài menu menu mà ko phải slide thì đóng menu
*******************************************************/
document.addEventListener("click", function(event) {
if( typeof event.target.closest == "undefined" )
return;
// Nếu như click vào ngoài menu thì sẽ đóng menu
if( event.target.closest(".naviman_app ul li ul.children") == null && event.target.closest(".naviman_app .naviItem") == null ) {
console.log("Click out of the menu");
if ( window._openingMenuItem && window._openingMenuKind && window._openingEmbedId ) { // Giả lập việc bấm vào đóng sub menu
naviman.showLevel2Items(
window._openingMenuItem,
window._openingMenuKind,
window._openingEmbedId
);
}else {
document.querySelectorAll('.naviman_app ul li ul.children').forEach((item) => {
item.style.display = "none";
});
// TODO
// Nếu chưa load được file JS này thì có thể lỗi
naviman.Helper.hideNaviOverlay();
}
}
});
/*******************************************************
Fix cho việc click vào menu thì sẽ đóng slide/hambuger menu
*******************************************************/
document.addEventListener("click", function(event) {
const isCloseBtn = event.target.closest(".naviItem .hamburger_close");
const isOverlay = event.target.closest(".naviman_app_overlay_global");
if (isCloseBtn || isOverlay) {
document.querySelectorAll(".naviItem.CONTEXT_SLIDE").forEach((item) => {
item.style.visibility = "hidden";
});
document.body.style.overflow = "initial";
const overlay = document.querySelector(".naviman_app_overlay_global");
if (overlay) {
overlay.style.display = "none";
}
// console.log("Slide menu closed by click on close button or overlay");
}
});
} // End of click out of menu
/**********************************************************
Dành cho fullExpand đảm bảo để dropdown menu
sẽ luôn luôn duy trì vị trí ở dưới parent menu.
***********************************************************/
function updateFullExpandTop(fullExpandParent) {
if (!fullExpandParent) return "0px";
/* 1. Trường hợp cha của full expand ko có sticky, chỉ set là rect.bottom là top là đủ ****/
const rect = fullExpandParent.getBoundingClientRect();
let rawTop = rect.bottom;
/* 2. Trường hợp cha của full expand có sticky thì phải trừ đi vị trí sticky OffsetFromTop. */
let el = fullExpandParent.parentElement;
let maxDepth = 20;
while (el && maxDepth-- > 0 && el !== document.body) {
const style = window.getComputedStyle(el);
if (style.position === "sticky") {
const stickyRect = el.getBoundingClientRect();
const stickyOffsetFromTop = stickyRect.top;
/*console.log("Có sticky ");
console.log(el);
console.log(stickyOffsetFromTop);*/
// Có thể gặp nhiều case có sticky nhưng lại gỉa, khi đó stickyOffsetFromTop < 0 và sẽ bị bỏ qua
if( stickyOffsetFromTop > 0 )
rawTop = rawTop - stickyOffsetFromTop;
break; // chỉ xử lý sticky đầu tiên
}
el = el.parentElement;
}
return rawTop + "px";
}
function maintainFullExpandDropdownPosition(dropdownFullExpand, insertMethod = "PublishToPlace") {
function updatePosition() {
let parent = dropdownFullExpand.parentElement;
if (parent) {
let rect = parent.getBoundingClientRect();
// console.log(rect);
if( insertMethod == "PublishToPlace" )
dropdownFullExpand.style.top = updateFullExpandTop(dropdownFullExpand.parentElement); // rect.bottom + "px";
else
if( insertMethod == "InsertToSection" ) {
/* Đối với một số mega menu lỗi hiển thị, thì tính 1 cái gap rồi trừ đi
Nó sẽ khiến cho có 1 đoạn delay chút xíu và tạo cảm giác sóng trên megamenu
--------------------------------------------------------------------------*/
dropdownFullExpand.style.opacity = "0";
dropdownFullExpand.style.top = rect.top + "px";
var gap = (dropdownFullExpand.getBoundingClientRect().top + rect.height) - rect.bottom;
if( gap > 0 ) {
dropdownFullExpand.style.top = (rect.bottom - gap ) + "px";
}else
dropdownFullExpand.style.top = rect.bottom + "px";
dropdownFullExpand.style.opacity = "1";
/*--------------------------------------------------------------------------*/
}
} else {
//console.warn("Dropdown has no parent element.");
}
}
updatePosition();
window.addEventListener("scroll", updatePosition);
window.addEventListener("resize", updatePosition);
}
/**********************************************************
Fix vị trí dành cho badge luôn ở góc phải trên của icon/image
***********************************************************/
/**********************************************************
Fix cho menu mobile megamenu dropdown thì khi expand ra thì ko cho phép scroll page
***********************************************************/
if (!window._fixMobileMegamenuScroll) {
window._fixMobileMegamenuScroll = true;
const waitForOverlay = () => {
const overlay = document.querySelector('.naviman_app_overlay');
if (!overlay) {
setTimeout(waitForOverlay, 100);
return;
}
const checkOverlayVisibility = () => {
const display = window.getComputedStyle(overlay).display;
const isVisible = display !== 'none';
document.body.style.overflow = isVisible ? 'hidden' : '';
};
const observer = new MutationObserver(checkOverlayVisibility);
observer.observe(overlay, {
attributes: true,
attributeFilter: ['style', 'class']
});
checkOverlayVisibility();
};
document.addEventListener('DOMContentLoaded', waitForOverlay);
}
var naviLanguage = (function(){
/* var countryList = {
'ab' : 'Abkhazian',
'aa' : 'Afar',
'af' : 'Afrikaans',
'ak' : 'Akan',
'sq' : 'Albanian',
'am' : 'Amharic',
'ar' : 'Arabic',
'an' : 'Aragonese',
'hy' : 'Armenian',
'as' : 'Assamese',
'av' : 'Avaric',
'ae' : 'Avestan',
'ay' : 'Aymara',
'az' : 'Azerbaijani',
'bm' : 'Bambara',
'ba' : 'Bashkir',
'eu' : 'Basque',
'be' : 'Belarusian',
'bn' : 'Bengali',
'bh' : 'Bihari languages',
'bi' : 'Bislama',
'bs' : 'Bosnian',
'br' : 'Breton',
'bg' : 'Bulgarian',
'my' : 'Burmese',
'ca' : 'Catalan, Valencian',
'km' : 'Central Khmer',
'ch' : 'Chamorro',
'ce' : 'Chechen',
'ny' : 'Chichewa, Chewa, Nyanja',
'zh' : 'Chinese',
'cu' : 'Church Slavonic, Old Bulgarian, Old Church Slavonic',
'cv' : 'Chuvash',
'kw' : 'Cornish',
'co' : 'Corsican',
'cr' : 'Cree',
'hr' : 'Croatian',
'cs' : 'Czech',
'da' : 'Danish',
'dv' : 'Divehi, Dhivehi, Maldivian',
'nl' : 'Dutch, Flemish',
'dz' : 'Dzongkha',
'en' : 'English',
'eo' : 'Esperanto',
'et' : 'Estonian',
'ee' : 'Ewe',
'fo' : 'Faroese',
'fj' : 'Fijian',
'fi' : 'Finnish',
'fr' : 'French',
'ff' : 'Fulah',
'gd' : 'Gaelic, Scottish Gaelic',
'gl' : 'Galician',
'lg' : 'Ganda',
'ka' : 'Georgian',
'de' : 'German',
'ki' : 'Gikuyu, Kikuyu',
'el' : 'Greek (Modern)',
'kl' : 'Greenlandic, Kalaallisut',
'gn' : 'Guarani',
'gu' : 'Gujarati',
'ht' : 'Haitian, Haitian Creole',
'ha' : 'Hausa',
'he' : 'Hebrew',
'hz' : 'Herero',
'hi' : 'Hindi',
'ho' : 'Hiri Motu',
'hu' : 'Hungarian',
'is' : 'Icelandic',
'io' : 'Ido',
'ig' : 'Igbo',
'id' : 'Indonesian',
'ia' : 'Interlingua (International Auxiliary Language Association)',
'ie' : 'Interlingue',
'iu' : 'Inuktitut',
'ik' : 'Inupiaq',
'ga' : 'Irish',
'it' : 'Italian',
'ja' : 'Japanese',
'jv' : 'Javanese',
'kn' : 'Kannada',
'kr' : 'Kanuri',
'ks' : 'Kashmiri',
'kk' : 'Kazakh',
'rw' : 'Kinyarwanda',
'kv' : 'Komi',
'kg' : 'Kongo',
'ko' : 'Korean',
'kj' : 'Kwanyama, Kuanyama',
'ku' : 'Kurdish',
'ky' : 'Kyrgyz',
'lo' : 'Lao',
'la' : 'Latin',
'lv' : 'Latvian',
'lb' : 'Letzeburgesch, Luxembourgish',
'li' : 'Limburgish, Limburgan, Limburger',
'ln' : 'Lingala',
'lt' : 'Lithuanian',
'lu' : 'Luba-Katanga',
'mk' : 'Macedonian',
'mg' : 'Malagasy',
'ms' : 'Malay',
'ml' : 'Malayalam',
'mt' : 'Maltese',
'gv' : 'Manx',
'mi' : 'Maori',
'mr' : 'Marathi',
'mh' : 'Marshallese',
'ro' : 'Moldovan, Moldavian, Romanian',
'mn' : 'Mongolian',
'na' : 'Nauru',
'nv' : 'Navajo, Navaho',
'nd' : 'Northern Ndebele',
'ng' : 'Ndonga',
'ne' : 'Nepali',
'se' : 'Northern Sami',
'no' : 'Norwegian',
'nb' : 'Norwegian Bokmål',
'nn' : 'Norwegian Nynorsk',
'ii' : 'Nuosu, Sichuan Yi',
'oc' : 'Occitan (post 1500)',
'oj' : 'Ojibwa',
'or' : 'Oriya',
'om' : 'Oromo',
'os' : 'Ossetian, Ossetic',
'pi' : 'Pali',
'pa' : 'Panjabi, Punjabi',
'ps' : 'Pashto, Pushto',
'fa' : 'Persian',
'pl' : 'Polish',
'pt' : 'Portuguese',
'qu' : 'Quechua',
'rm' : 'Romansh',
'rn' : 'Rundi',
'ru' : 'Russian',
'sm' : 'Samoan',
'sg' : 'Sango',
'sa' : 'Sanskrit',
'sc' : 'Sardinian',
'sr' : 'Serbian',
'sn' : 'Shona',
'sd' : 'Sindhi',
'si' : 'Sinhala, Sinhalese',
'sk' : 'Slovak',
'sl' : 'Slovenian',
'so' : 'Somali',
'st' : 'Sotho, Southern',
'nr' : 'South Ndebele',
'es' : 'Spanish, Castilian',
'su' : 'Sundanese',
'sw' : 'Swahili',
'ss' : 'Swati',
'sv' : 'Swedish',
'tl' : 'Tagalog',
'ty' : 'Tahitian',
'tg' : 'Tajik',
'ta' : 'Tamil',
'tt' : 'Tatar',
'te' : 'Telugu',
'th' : 'Thai',
'bo' : 'Tibetan',
'ti' : 'Tigrinya',
'to' : 'Tonga (Tonga Islands)',
'ts' : 'Tsonga',
'tn' : 'Tswana',
'tr' : 'Turkish',
'tk' : 'Turkmen',
'tw' : 'Twi',
'ug' : 'Uighur, Uyghur',
'uk' : 'Ukrainian',
'ur' : 'Urdu',
'uz' : 'Uzbek',
've' : 'Venda',
'vi' : 'Vietnamese',
'vo' : 'Volap_k',
'wa' : 'Walloon',
'cy' : 'Welsh',
'fy' : 'Western Frisian',
'wo' : 'Wolof',
'xh' : 'Xhosa',
'yi' : 'Yiddish',
'yo' : 'Yoruba',
'za' : 'Zhuang, Chuang',
'zu' : 'Zulu'
}; */
function stringByLanguage( str ) {
if( str == null )
return "";
str = String(str);
str = str.trim();
let arr = str.match(/<.*?>/g);
if( arr == null )
return str;
if( arr.length == 0 )
return str;
// 1. Loại bỏ các phần có
let localizeStr = str;
arr.forEach((item) => {
localizeStr = localizeStr.replace( item, "" );
});
localizeStr = localizeStr.trim();
// 2. Tạo một array gồm language_code:string
langStr = [];
langStr.push(["localize", localizeStr]);
arr.forEach((item) => {
let child = item.replace( "<", "" ).replace( "/>", "" ).replace( ">", "" );
var index = child.indexOf(':');
if( index > -1 ) {
var child_array = [child.slice(0, index).trim(), child.slice(index + 1).trim()];
if(child_array.length == 2)
if( child_array[0] != "" )
langStr.push([child_array[0], child_array[1]]);
}
});
// 3. So sánh trong danh sách trả về
let currentLang = currentLanguage();
// console.log("Language code: " + currentLang);
var output = localizeStr;
langStr.forEach((lang) => {
if( lang[0] == currentLang ) {
output = lang[1];
return;
}
});
return output;
}
/*function currentLanguage() {
let pathName = document.location.pathname;
if( pathName.length < 3 )
return "localize";
for (var lang in countryList) {
var langCom = "/" + lang;
if( pathName.substring(0, 3).toLowerCase() == langCom.toLowerCase() ) {
if( pathName.length == 3 )
return lang;
if( pathName.length > 3 )
if( pathName[3] == "/" || pathName[3] == "&" || pathName[3] == "#" || pathName[3] == "?" || pathName[3] == "%" )
return lang;
}
}
return "localize";
}*/
function currentLanguage() {
let pathName = document.location.pathname;
// Loại bỏ domain và lấy phần đầu tiên sau dấu "/"
let pathParts = pathName.split('/').filter(part => part.length > 0);
// Kiểm tra nếu không có đủ phần sau dấu "/"
if (pathParts.length < 1) {
return "localize";
}
// Lấy phần đầu tiên sau dấu "/" và trả về nó mà không cần kiểm tra trong countryList
return pathParts[0];
}
return {
Name: "Naviman Language",
stringByLanguage: stringByLanguage,
currentLanguage: currentLanguage,
};
})();
/* DEPLOY DELETE.BEGIN */
// naviman.turnOffLocalStorage();
/* DEPLOY DELETE.END */
var naviman_runApp = function (e) {
/** 1.Link CSS & icons **************************************/
function linkCSSToHead(href) {
// Kiểm tra xem file CSS đã tồn tại trong chưa
if (!document.querySelector(`link[href="${href}"]`)) {
const link = document.createElement('link');
link.href = href;
link.type = "text/css";
link.rel = 'stylesheet';
// Khi file CSS được tải xong, log ra thông báo (tùy chọn)
link.onload = function () {
// console.log(`CSS file ${href} loaded successfully.`);
};
// Thêm phần tử vào phần
document.head.appendChild(link);
} else {
// console.log(`CSS file ${href} is already linked on this page.`);
}
}
function linkPreloadCSSToHead(href) {
// Kiểm tra xem file CSS đã tồn tại trong chưa
if (!document.querySelector(`link[href="${href}"]`)) {
// Tạo thẻ với rel="preload" để preload CSS
const preloadLink = document.createElement('link');
preloadLink.href = href;
preloadLink.rel = 'preload';
preloadLink.as = 'style';
// Thêm thẻ preload vào
document.head.appendChild(preloadLink);
// Sau khi preload xong, thêm thẻ
const link = document.createElement('link');
link.href = href;
link.type = "text/css";
link.rel = 'stylesheet';
// Khi file CSS được tải xong, log ra thông báo (tùy chọn)
link.onload = function () {
// console.log(`CSS file ${href} loaded successfully.`);
};
// Thêm phần tử vào phần
document.head.appendChild(link);
} else {
// console.log(`CSS file ${href} is already linked on this page.`);
}
}
linkCSSToHead( naviman_css );
linkCSSToHead( "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" );
linkCSSToHead( "https://cdn.jsdelivr.net/npm/remixicon@4.5.0/fonts/remixicon.min.css" );
/** 2.Get variables **************************************/
var shop = document.currentScript.getAttribute('shop');
var embed_id = '';
if(document.currentScript.getAttribute('embed_id') != null)
embed_id = document.currentScript.getAttribute('embed_id');
var section_setting = [];
section_setting['embed_id'] = '';
section_setting['not_sticky'] = false;
section_setting['embed_title'] = '';
section_setting['embed_is_full'] = false;
section_setting['embed_margin'] = "0 0 0 0";
if(embed_id != '') {
var not_sticky = false;
var embed_title = "";
var embed_is_full = false;
var embed_margin = "0 0 0 0";
if (document.currentScript.getAttribute('not_sticky') != null)
not_sticky = document.currentScript.getAttribute('not_sticky');
if(embed_id != '') if(document.currentScript.getAttribute('embed_title') != null)
embed_title = document.currentScript.getAttribute('embed_title');
if(embed_id != '') if(document.currentScript.getAttribute('embed_is_full') != null)
embed_is_full = document.currentScript.getAttribute('embed_is_full');
if(embed_id != '') if(document.currentScript.getAttribute('embed_margin') != null)
embed_margin = document.currentScript.getAttribute('embed_margin');
section_setting['embed_id'] = embed_id.trim();
section_setting['not_sticky'] = not_sticky;
section_setting['embed_title'] = embed_title.trim();
section_setting['embed_is_full'] = embed_is_full;
section_setting['embed_margin'] = embed_margin;
}
// console.log(section_setting);
/*****************
Mỗi khi gặp đoạn mã này thì sẽ chạy một lần runNaviman. Data có thể là một danh sách hoặc 1 item
- Nếu all: Chạy for cho nhiều item.
- Nếu section:
1. Nếu sticky thì chạy bình thường (for vô nghĩa)
2. Nếu ko sticky thì bổ sung mã CSS (for vô nghĩa)
***************/
function runNaviman( data, shopinfo ) {
naviman.init();
if( isNeedCartCount(data) ) {
naviman.asyncGetCart().then( function(result) {
// console.log("Cart count: " + result.item_count );
window.addEventListener('SCE:mutate', (event) => {
naviman.checkAndUpdateCartCount();
});
naviman.setCartCount( result.item_count );
naviman.drawBottomNav(data, naviman_domain, shop, embed_id, section_setting);
naviman.generateActiveItems();
if( result.item_count == 0 ) {
naviman.updateCartCount( result.item_count );
}
});
}else {
naviman.drawBottomNav(data, naviman_domain, shop, embed_id, section_setting);
naviman.generateActiveItems();
}
}
var api_url = naviman_json_cdn + "/" + shop.replace(".myshopify.com", '') + ".all.json";
if( embed_id != '' )
api_url = naviman_json_cdn + "/" + shop.replace(".myshopify.com", '') + "." + embed_id + ".json";
// TODO: Chỗ này không có là không chạy đúng
// api_url += "?v=" + Math.random();
var api_shopinfo_url = naviman_json_cdn + "/" + shop.replace(".myshopify.com", '') + ".info.json";
api_shopinfo_url += "?v=" + Math.random();
function logCache( kind, key, value ) {
console.log( kind + ": " + key);
console.log(value);
}
// Start here ===============================================<<
function clearNaviSectionStorage() {
if( !naviman.isLocalStorageSupported() )
return;
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.includes('naviplus')) {
localStorage.removeItem(key);
i--;
}
}
}
function runApplication(shopinfo) {
var jsonData = naviman.getSessionStorage(api_url);
var jsonUpdateVersion = 0;
if( naviman.getSessionStorage("jsonUpdateVersion") != null )
jsonUpdateVersion = naviman.getSessionStorage("jsonUpdateVersion");
var isNeedRequestServer = false;
if( jsonData == null )
isNeedRequestServer = true;
if( shopinfo["update_version"] != jsonUpdateVersion ) {
console.log("There is a new version of Navi+ data! Loading from server...");
clearNaviSectionStorage();
isNeedRequestServer = true;
}
if( isNeedRequestServer ) {
fetch(api_url + "?v=" + Math.random())
.then((response) => response.json())
.then((json) => {
logCache( "[Server]", api_url, json );
// Set json to localStorate
naviman.setSessionStorage(api_url, json, naviman_cache_miniseconds);
// Set update version to localStorate
naviman.setSessionStorage("jsonUpdateVersion", shopinfo["update_version"], naviman_cache_miniseconds);
runNaviman(json, shopinfo);
});
}else {
// logCache( "From local", api_url, jsonData );
console.log("[Session storage] " , api_url);
runNaviman(jsonData, shopinfo);
}
}
//******************************************************************
// LẤY THÔNG TIN VỀ BIẾN TOÀN CỤC SHOPINFO ĐỂ CHẠY ỨNG DỤNG
//******************************************************************
if (!navihelper.windowVar.isExisted('shopinfoPromise')) {
navihelper.windowVar.set('shopinfoPromise', null);
}
if (!navihelper.windowVar.isExisted('shopinfo')) {
if (!navihelper.windowVar.get('shopinfoPromise')) {
// Nếu chưa có dữ liệu và chưa có Promise, thực hiện fetch
const shopinfoPromise = fetch(api_shopinfo_url)
.then((response) => response.json())
.then((shopinfo) => {
navihelper.windowVar.set('shopinfo', shopinfo); // Lưu dữ liệu
console.log(shopinfo);
return shopinfo;
})
.catch((error) => {
console.error("Error fetching shop info:", error);
throw error;
});
navihelper.windowVar.set('shopinfoPromise', shopinfoPromise);
}
navihelper.windowVar.get('shopinfoPromise').then((shopinfo) => {
runApplication(shopinfo);
});
} else {
runApplication(navihelper.windowVar.get('shopinfo'));
}
//******************************************************************
// Start here ===============================================>>
function containsBadgeIsCart(arr) {
for (let i = 0; i < arr.length; i++) {
const item = arr[i];
if( naviman.isHadValue( item["badgeiscart"] ) )
if( item["badgeiscart"] == 1 || item["badgeiscart"] == "1" ) {
return true;
}
if (Array.isArray(item["children"]))
if (item["children"].length > 0) {
if (containsBadgeIsCart(item["children"])) {
return true;
}
}
}
return false;
}
function isNeedCartCount( data ) {
var isNeed = false;
data.forEach((naviItem) => {
if( containsBadgeIsCart( naviItem["data"]["dragdrop"] ) ) {
isNeed = true;
return;
}
});
return isNeed;
}
/** 3.Get API data **************************************/
function jsonp(uri) {
return new Promise(function(resolve, reject) {
var id = '_' + Math.round(10000 * Math.random());
var callbackName = 'jsonp_callback_' + id;
window[callbackName] = function(data) {
delete window[callbackName];
var ele = document.getElementById(id);
ele.parentNode.removeChild(ele);
resolve(data);
}
var src = uri + '&callback=' + callbackName;
var script = document.createElement('script');
script.src = src;
script.id = id;
script.addEventListener('error', reject);
(document.getElementsByTagName('head')[0] || document.body || document.documentElement).appendChild(script)
});
}
};
naviman_runApp();