Packages
phoenix_kit
1.7.18
1.7.209
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
priv/static/assets/phoenix_kit.js
/**
* PhoenixKit JavaScript
*
* Main entry point for all PhoenixKit JavaScript functionality.
* Auto-imports all PhoenixKit JS modules and exposes hooks for LiveView.
*
* This file is copied to your assets/js/vendor/ directory during installation.
*
* SETUP: Import in your app.js BEFORE creating liveSocket:
*
* import "./vendor/phoenix_kit"
*
* let liveSocket = new LiveSocket("/live", Socket, {
* hooks: { ...window.PhoenixKitHooks, ...Hooks },
* // ... other options
* })
*
* That's it! All PhoenixKit hooks are automatically registered.
*/
// Import the sortable module (same vendor directory)
import "./phoenix_kit_sortable.js";
// Import the cookie consent module
import "./phoenix_kit_consent.js";
(function() {
"use strict";
// Prevent double initialization
if (window.PhoenixKitInitialized) return;
window.PhoenixKitInitialized = true;
// Initialize hooks collection
window.PhoenixKitHooks = window.PhoenixKitHooks || {};
// Register SortableGrid hook (set by phoenix_kit_sortable.js)
if (window.SortableGridHook) {
window.PhoenixKitHooks.SortableGrid = window.SortableGridHook;
}
// Register CookieConsent hook (set by phoenix_kit_consent.js)
// This hook is registered directly in the consent module
// ResetSelect hook - resets select element to first option on push event
window.PhoenixKitHooks.ResetSelect = {
mounted() {
this.handleEvent("reset_select", ({id}) => {
if (this.el.id === id) {
this.el.selectedIndex = 0;
}
});
}
};
// TimeAgo hook - client-side relative time updates with variable interval
// Updates frequently for recent times, less often for older times (accessibility-friendly)
window.PhoenixKitHooks.TimeAgo = {
mounted() {
const timestamp = this.el.getAttribute("data-datetime");
if (!timestamp) return;
// Validate timestamp before scheduling updates
const parsed = new Date(timestamp);
if (isNaN(parsed.getTime())) {
console.warn("TimeAgo: Invalid timestamp", timestamp);
return;
}
this.timestamp = timestamp;
this.parsedTime = parsed.getTime(); // Cache parsed epoch for efficiency
this.update();
this.scheduleUpdate();
},
destroyed() {
this.clearTimer();
},
// Clear timer when LiveView temporarily disconnects
disconnected() {
this.clearTimer();
},
// Restart timer when LiveView reconnects
reconnected() {
if (this.timestamp) {
this.update();
this.scheduleUpdate();
}
},
updated() {
// Handle LiveView updates (e.g., new datetime value)
const newTimestamp = this.el.getAttribute("data-datetime");
if (newTimestamp && newTimestamp !== this.timestamp) {
const parsed = new Date(newTimestamp);
if (isNaN(parsed.getTime())) return;
this.timestamp = newTimestamp;
this.parsedTime = parsed.getTime();
this.update();
this.scheduleUpdate();
}
},
clearTimer() {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
},
scheduleUpdate() {
this.clearTimer();
const interval = this.getInterval();
this.timer = setTimeout(() => {
this.update();
this.scheduleUpdate();
}, interval);
},
update() {
const text = this.getRelativeTime();
if (text && this.el.textContent !== text) {
this.el.textContent = text;
}
},
getRelativeTime() {
const now = Date.now();
const seconds = Math.round((now - this.parsedTime) / 1000);
if (seconds < 0) return "just now";
if (seconds < 60) return seconds + "s ago";
const minutes = Math.round(seconds / 60);
if (minutes < 60) return minutes + "m ago";
const hours = Math.round(minutes / 60);
if (hours < 24) return hours + "h ago";
const days = Math.round(hours / 24);
return days + "d ago";
},
getInterval() {
const seconds = Math.round((Date.now() - this.parsedTime) / 1000);
// Update every second for first minute
if (seconds < 60) return 1000;
// Update every 30 seconds for first hour
if (seconds < 3600) return 30000;
// Update every 5 minutes for first day
if (seconds < 86400) return 300000;
// Update every hour for older times
return 3600000;
}
};
// Log successful initialization in development
if (typeof console !== "undefined" && console.debug) {
var hookCount = Object.keys(window.PhoenixKitHooks).length;
if (hookCount > 0) {
console.debug("[PhoenixKit] Initialized with " + hookCount + " hook(s):", Object.keys(window.PhoenixKitHooks));
}
}
})();