Browse Source

Performance improvements

master
Igor Zhukov 10 years ago
parent
commit
ef3fc51e53
  1. 4
      app/css/app.css
  2. 1
      app/index.html
  3. 1
      app/js/app.js
  4. 5
      app/js/directives.js
  5. 4
      app/js/services.js
  6. 2
      app/partials/chat_modal.html
  7. 32
      app/partials/dialog.html
  8. 4
      app/partials/head.html
  9. 59
      app/partials/im.html
  10. 62
      app/partials/message.html
  11. 2
      app/partials/settings_modal.html
  12. 321
      app/vendor/bindonce/bindonce.js

4
app/css/app.css

@ -1413,6 +1413,10 @@ span.emoji { @@ -1413,6 +1413,10 @@ span.emoji {
font-size: 1.5em;
padding: 0 50px;
}
.im_history_to_bottom .im_history_not_selected,
.im_history_to_bottom .im_history_empty {
display: none;
}
.im_send_panel_wrap {
max-width: 526px;

1
app/index.html

@ -36,6 +36,7 @@ @@ -36,6 +36,7 @@
<script type="text/javascript" src="vendor/angular/angular-animate.js"></script>
<script type="text/javascript" src="vendor/angular/angular-sanitize.js"></script>
<script type="text/javascript" src="vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js"></script>
<script type="text/javascript" src="vendor/bindonce/bindonce.js"></script>
<script type="text/javascript" src="vendor/jsbn/jsbn_combined.js"></script>
<script type="text/javascript" src="vendor/cryptoJS/crypto.js"></script>

1
app/js/app.js

@ -30,6 +30,7 @@ angular.module('myApp', [ @@ -30,6 +30,7 @@ angular.module('myApp', [
'ngAnimate',
'ngSanitize',
'ui.bootstrap',
'pasvaz.bindonce',
'mtproto.services',
'myApp.filters',
'myApp.services',

5
app/js/directives.js

@ -318,6 +318,9 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -318,6 +318,9 @@ angular.module('myApp.directives', ['myApp.filters'])
});
function updateSizes (heightOnly) {
if (!element.is(':visible') || !$(element[0].parentNode).is(':visible')) {
return;
}
if ($(sendFormWrap).is(':visible')) {
$(sendFormWrap).css({
height: $(sendForm).height()
@ -851,7 +854,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -851,7 +854,7 @@ angular.module('myApp.directives', ['myApp.filters'])
})
.directive('myTypingDots', function($interval) {
.directive('myLoadingDots', function($interval) {
return {
link: link,

4
app/js/services.js

@ -671,7 +671,7 @@ angular.module('myApp.services', []) @@ -671,7 +671,7 @@ angular.module('myApp.services', [])
}
})
.service('AppMessagesManager', function ($q, $rootScope, $location, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager) {
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager) {
var messagesStorage = {};
var messagesForHistory = {};
@ -1482,6 +1482,8 @@ angular.module('myApp.services', []) @@ -1482,6 +1482,8 @@ angular.module('myApp.services', [])
message.richMessage = RichTextProcessor.wrapRichText(message.message.substr(0, 64), {noLinks: true, noLinebreaks: true});
}
message.dateText = $filter('dateOrTime')(message.date);
return messagesForDialogs[msgID] = message;
}

2
app/partials/chat_modal.html

@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
thumb="chatFull.thumb"
/>
<div class="chat_modal_photo_change_wrap" ng-if="chatFull.chat._ != 'chatForbidden' &amp;&amp; !chatFull.chat.left">
<div ng-if="photo.updating" class="chat_modal_photo_loading">Updating<span my-typing-dots></span></div>
<div ng-if="photo.updating" class="chat_modal_photo_loading">Updating<span my-loading-dots></span></div>
<div ng-if="!photo.updating">
<div class="chat_modal_photo_update_link">
<input my-file-upload type="file" multiple="false" class="im_attach_input" size="120" multiple="false" accept="image/x-png, image/png, image/gif, image/jpeg" />

32
app/partials/dialog.html

@ -1,9 +1,7 @@ @@ -1,9 +1,7 @@
<a class="im_dialog" ng-click="dialogSelect(dialogMessage.peerString)">
<div class="im_dialog_meta pull-right text-right">
<div class="im_dialog_date">
{{dialogMessage.date | dateOrTime}}
</div>
<div class="im_dialog_date" ng-bind="dialogMessage.dateText"></div>
<span
class="im_dialog_badge badge"
ng-show="dialogMessage.unreadCount > 0 &amp;&amp; !dialogMessage.out"
@ -25,11 +23,11 @@ @@ -25,11 +23,11 @@
<div class="im_dialog_message_wrap">
<div class="im_dialog_peer">
<span class="im_dialog_chat" ng-if="dialogMessage.chatID">
<i class="icon icon-group"></i> <span ng-bind-html="dialogMessage.peerData.rTitle"></span>
<div class="im_dialog_peer" ng-switch="dialogMessage.peerID > 0">
<span class="im_dialog_user" ng-switch-when="true" ng-bind-html="dialogMessage.peerData.rFullName"></span>
<span class="im_dialog_chat" ng-switch-default>
<span ng-bind-html="dialogMessage.peerData.rTitle"></span>
</span>
<span class="im_dialog_user" ng-if="dialogMessage.peerID > 0" ng-bind-html="dialogMessage.peerData.rFullName"></span>
</div>
<div class="im_dialog_message">
@ -59,22 +57,22 @@ @@ -59,22 +57,22 @@
<span ng-switch-when="messageActionChatEditPhoto">changed group photo</span>
<span ng-switch-when="messageActionChatDeletePhoto">removed group photo</span>
<span ng-switch-when="messageActionChatAddUser">
<span ng-if="dialogMessage.from_id != dialogMessage.action.user_id">
invited <span ng-bind-html="dialogMessage.action.user.rFullName"></span>
</span>
<span ng-if="dialogMessage.from_id == dialogMessage.action.user_id">
<span ng-switch-when="messageActionChatAddUser" ng-switch="dialogMessage.from_id == dialogMessage.action.user_id">
<span ng-switch-when="true">
returned to group
</span>
<span ng-switch-default>
invited <span ng-bind-html="dialogMessage.action.user.rFullName"></span>
</span>
</span>
<span ng-switch-when="messageActionChatDeleteUser">
<span ng-if="dialogMessage.from_id != dialogMessage.action.user_id">
kicked <span ng-bind-html="dialogMessage.action.user.rFullName"></span>
</span>
<span ng-if="dialogMessage.from_id == dialogMessage.action.user_id">
<span ng-switch-when="messageActionChatDeleteUser" ng-switch="dialogMessage.from_id == dialogMessage.action.user_id">
<span ng-switch-when="true">
left group
</span>
<span ng-switch-default>
kicked <span ng-bind-html="dialogMessage.action.user.rFullName"></span>
</span>
</span>
</span>

4
app/partials/head.html

@ -22,9 +22,9 @@ @@ -22,9 +22,9 @@
<div class="navbar-collapse" collapse="navbarCollapsed">
<ul ng-if="offline" class="nav navbar-nav navbar-offline">
<li ng-show="!offlineConnecting"><span class="navbar-offline-text">Waiting for network<span my-typing-dots></span></span></li>
<li ng-show="!offlineConnecting"><span class="navbar-offline-text">Waiting for network<span my-loading-dots></span></span></li>
<li ng-show="!offlineConnecting"><a href="" ng-click="retryOnline()">Retry</a></li>
<li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-typing-dots></span></span></li>
<li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-loading-dots></span></span></li>
</ul>
<ul ng-if="!offline" class="nav navbar-nav navbar-right">

59
app/partials/im.html

@ -63,7 +63,7 @@ @@ -63,7 +63,7 @@
Please select a chat to start messaging
</div>
<div ng-show="!state.notSelected &amp;&amp; !state.loaded" class="im_history_not_selected" my-vertical-position="0.3">
Loading history <span my-typing-dots></span>
Loading history<span my-loading-dots></span>
</div>
<div ng-show="state.loaded">
@ -90,25 +90,26 @@ @@ -90,25 +90,26 @@
<strong class="im_history_panel_return_count" ng-show="missedCount > 0">+{{missedCount}}</strong>
</a>
<h4 ng-show="mediaType !== false" ng-switch="mediaType">
<span ng-switch-when="photos">Photos</span>
<span ng-switch-when="video">Videos</span>
<span ng-switch-when="documents">Documents</span>
</h4>
<h4 ng-show="mediaType === false &amp;&amp; historyPeer.id < 0" ng-click="showPeerInfo()">
<span ng-bind-html="historyPeer.data.rTitle"></span>
<small class="im_chat_users">
<ng-pluralize count="historyPeer.data.participants_count"
when="{'0': 'No members', 'one': '1 member', 'other': '{} members'}">
</ng-pluralize>
</small>
</h4>
<h4 ng-show="mediaType === false &amp;&amp; historyPeer.id > 0" ng-click="showPeerInfo()">
<span ng-bind-html="historyPeer.data.rFullName"></span>
<small class="im_peer_online">{{historyPeer.data | userStatus}}</small>
</h4>
<div ng-switch="mediaType">
<h4 ng-switch-when="photos">Photos</h4>
<h4 ng-switch-when="video">Videos</h4>
<h4 ng-switch-when="documents">Documents</h4>
<h4 ng-switch-default ng-switch="historyPeer.id > 0">
<div ng-switch-when="true">
<span ng-bind-html="historyPeer.data.rFullName"></span>
<small class="im_peer_online">{{historyPeer.data | userStatus}}</small>
</div>
<div ng-switch-default>
<span ng-bind-html="historyPeer.data.rTitle"></span>
<small class="im_chat_users">
<ng-pluralize count="historyPeer.data.participants_count"
when="{'0': 'No members', 'one': '1 member', 'other': '{} members'}">
</ng-pluralize>
</small>
</div>
</h4>
</div>
</div>
@ -127,13 +128,13 @@ @@ -127,13 +128,13 @@
No messages here yet...
</div>
<div class="im_history_messages">
<div class="im_history_message_wrap" my-message ng-repeat="historyMessage in history"></div>
<div class="im_history_message_wrap" my-message bindonce ng-repeat="historyMessage in history"></div>
</div>
</div>
<div class="im_history_typing_wrap">
<div class="im_history_typing" ng-show="typing.user &amp;&amp; !mediaType">
<strong class="im_history_typing_author" ng-bind-html="typing.user.rFullName"></strong> is typing<span my-typing-dots></span>
<strong class="im_history_typing_author" ng-bind-html="typing.user.rFullName"></strong> is typing<span my-loading-dots></span>
</div>
</div>
@ -145,17 +146,13 @@ @@ -145,17 +146,13 @@
<div class="im_bottom_panel_wrap">
<div class="im_edit_panel_wrap clearfix" ng-show="selectActions" ng-class="{im_edit_panel_wrap_loaded: true}">
<div class="im_edit_panel_wrap clearfix" ng-show="selectActions">
<div class="im_edit_panel_border"></div>
<a class="im_edit_flush_link" ng-click="selectedFlush()" ng-show="historyPeer.id < 0">
Clear History
</a>
<a class="im_edit_flush_link" ng-click="selectedFlush()" ng-show="historyPeer.id > 0">
Delete Chat
</a>
<a class="im_edit_cancel_link" ng-click="selectedCancel()">
Cancel
<a class="im_edit_flush_link" ng-click="selectedFlush()" ng-switch="historyPeer.id > 0">
<span ng-switch-when="true">Delete Chat</span>
<span ng-switch-default>Clear History</span>
</a>
<a class="im_edit_cancel_link" ng-click="selectedCancel()">Cancel</a>
<div class="im_edit_selected_actions">
<a class="btn btn-primary im_edit_forward_btn" ng-click="selectedForward()">
Forward <strong class="im_selected_count" ng-show="selectedCount > 0" ng-bind="selectedCount"></strong>

62
app/partials/message.html

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
<div class="im_message_unread_split" ng-if="historyUnread &amp;&amp; historyUnread.beforeID == historyMessage.id">
<div class="im_message_unread_split" bo-if="historyUnread.beforeID == historyMessage.id" ng-show="historyUnread.beforeID == historyMessage.id">
<ng-pluralize count="historyUnread.count"
when="{'one': '1 unread message', 'other': '{} unread messages'}">
</ng-pluralize>
@ -7,51 +7,51 @@ @@ -7,51 +7,51 @@
<div class="im_message_outer_wrap" ng-class="{im_message_selected: selectedMsgs[historyMessage.id]}" ng-click="toggleMessage(historyMessage.id, $event.target)">
<div class="im_message_wrap clearfix">
<div class="im_message_wrap clearfix" bindonce>
<div class="im_service_message_wrap" ng-if="historyMessage._ == 'messageService'">
<div class="im_service_message_wrap" bo-if="historyMessage._ == 'messageService'">
<div class="im_service_message">
<a ng-click="openUser(historyMessage.from_id)" class="im_message_author" ng-bind-html="historyMessage.fromUser.rFullName"></a>
<span class="im_message_service" ng-switch="historyMessage.action['_']">
<span ng-switch-when="messageActionChatCreate">
<span class="im_message_service" bo-switch="historyMessage.action['_']">
<span bo-switch-when="messageActionChatCreate">
created the group &laquo;<strong>{{historyMessage.action.title}}</strong>&raquo;
</span>
<span ng-switch-when="messageActionChatEditTitle">
<span bo-switch-when="messageActionChatEditTitle">
changed group name to &laquo;<strong ng-bind-html="historyMessage.action.rTitle"></strong>&raquo;
</span>
<span ng-switch-when="messageActionChatEditPhoto">
<span bo-switch-when="messageActionChatEditPhoto">
changed group photo
</span>
<span ng-switch-when="messageActionChatDeletePhoto">
<span bo-switch-when="messageActionChatDeletePhoto">
removed group photo
</span>
<span ng-switch-when="messageActionChatAddUser">
<span ng-if="historyMessage.from_id != historyMessage.action.user_id">
<span bo-switch-when="messageActionChatAddUser">
<span bo-if="historyMessage.from_id != historyMessage.action.user_id">
invited <a ng-click="openUser(historyMessage.action.user_id)" ng-bind-html="historyMessage.action.user.rFullName"></a>
</span>
<span ng-if="historyMessage.from_id == historyMessage.action.user_id">
<span bo-if="historyMessage.from_id == historyMessage.action.user_id">
returned to group
</span>
</span>
<span ng-switch-when="messageActionChatDeleteUser">
<span ng-if="historyMessage.from_id != historyMessage.action.user_id">
<span bo-switch-when="messageActionChatDeleteUser">
<span bo-if="historyMessage.from_id != historyMessage.action.user_id">
kicked <a ng-click="openUser(historyMessage.action.user_id)" ng-bind-html="historyMessage.action.user.rFullName"></a>
</span>
<span ng-if="historyMessage.from_id == historyMessage.action.user_id">
<span bo-if="historyMessage.from_id == historyMessage.action.user_id">
left group
</span>
</span>
<span ng-switch-default>
<span bo-switch-default>
unsupported action {{historyMessage.action}}
</span>
</span>
</div>
<a ng-if="historyMessage.action._ == 'messageActionChatEditPhoto'" class="im_service_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.action.photo.id)">
<a bo-if="historyMessage.action._ == 'messageActionChatEditPhoto'" class="im_service_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.action.photo.id)">
<img
class="im_service_message_photo_thumb"
my-load-thumb
@ -63,15 +63,16 @@ @@ -63,15 +63,16 @@
</div>
<div class="im_content_message_wrap" ng-if="historyMessage._ != 'messageService'">
<div bindonce bo-if="historyMessage._ != 'messageService'" class="im_content_message_wrap">
<div class="im_content_message_select_area">
<i class="icon icon-select-tick"></i>
</div>
<a ng-click="historyMessage.send()" ng-if="historyMessage.error">
<a bo-if="historyMessage.pending || historyMessage.error" ng-click="historyMessage.send()" ng-show="historyMessage.error">
<i class="icon-message-status icon-message-status-error" tooltip="Try again"></i>
</a>
<i class="icon-message-status" ng-class="{'icon-message-status-unread': historyMessage.unread, 'icon-message-status-pending': historyMessage.pending}" ng-if="!historyMessage.error"></i>
<i bo-if="historyMessage.unread || historyMessage.pending" class="icon-message-status" ng-class="{'icon-message-status-unread': historyMessage.unread, 'icon-message-status-pending': historyMessage.pending}" ng-show="!historyMessage.error"></i>
<a ng-click="openUser(historyMessage.from_id)" class="im_message_from_photo pull-left">
<img
@ -81,20 +82,19 @@ @@ -81,20 +82,19 @@
/>
</a>
<div class="im_message_meta pull-right text-right">
<span class="im_message_date">{{historyMessage.date | dateOrTime}}</span>
<span class="im_message_date" bo-bind="historyMessage.date | dateOrTime"></span>
</div>
<div class="im_message_body">
<a class="im_message_author user_color_{{historyMessage.fromPhoto.num}}" ng-click="openUser(historyMessage.from_id)" ng-bind-html="historyMessage.fromUser.rFullName" ng-if="historyMessage.to_id.chat_id > 0"></a>
<a class="im_message_author" ng-click="openUser(historyMessage.from_id)" ng-bind-html="historyMessage.fromUser.rFirstName" ng-if="!historyMessage.to_id.chat_id"></a>
<a bo-if="historyMessage.to_id.chat_id > 0" class="im_message_author user_color_{{historyMessage.fromPhoto.num}}" ng-click="openUser(historyMessage.from_id)" ng-bind-html="historyMessage.fromUser.rFullName"></a>
<a bo-if="!historyMessage.to_id.chat_id" class="im_message_author" ng-click="openUser(historyMessage.from_id)" ng-bind-html="historyMessage.fromUser.rFirstName" ></a>
<div class="im_message_fwd_header" ng-if="historyMessage._ == 'messageForwarded'">
<div bo-if="historyMessage._ == 'messageForwarded'" class="im_message_fwd_header">
Forwarded message from <a class="im_message_fwd_author" ng-click="openUser(historyMessage.fwd_from_id)" ng-bind-html="historyMessage.fwdUser.rFirstName"></a>, <span class="im_message_fwd_date">{{historyMessage.fwd_date | dateOrTime}}</span>
</div>
<div class="im_message_media" ng-if="historyMessage.media &amp;&amp; historyMessage.media._ != 'messageMediaEmpty'" ng-switch="historyMessage.media._">
<div bo-if="historyMessage.media &amp;&amp; historyMessage.media._ != 'messageMediaEmpty'" class="im_message_media" ng-switch="historyMessage.media._">
<a ng-switch-when="messageMediaPhoto" class="im_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.media.photo.id)" style="width: {{historyMessage.media.photo.thumb.width}}px;">
<img
@ -147,8 +147,8 @@ @@ -147,8 +147,8 @@
<div ng-switch-when="messageMediaDocument" class="im_message_document" ng-class="{im_message_document_thumbed: !!historyMessage.media.document.thumb}">
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, false, historyMessage.media.document.withPreview)" ng-class="{im_message_document_link_disabled: historyMessage.media.document.progress.enabled}">
<i class="icon icon-document" ng-if="!historyMessage.media.document.thumb"></i>
<div class="im_message_document_thumb_wrap" ng-if="historyMessage.media.document.thumb">
<i class="icon icon-document" bo-if="!historyMessage.media.document.thumb"></i>
<div class="im_message_document_thumb_wrap" bo-if="historyMessage.media.document.thumb">
<img
class="im_message_document_thumb"
my-load-thumb
@ -173,7 +173,7 @@ @@ -173,7 +173,7 @@
</div>
<div class="im_message_document_actions" ng-if="!historyMessage.media.document.progress.enabled">
<a href="" ng-click="downloadDoc(historyMessage.media.document.id)">Download</a>
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, false, true)" ng-if="historyMessage.media.document.withPreview">Open</a>
<a href="" ng-click="downloadDoc(historyMessage.media.document.id, false, true)" bo-if="historyMessage.media.document.withPreview">Open</a>
</div>
<div class="im_message_download_progress_wrap" ng-if="historyMessage.media.document.progress.enabled">
<div class="progress tg_down_progress">
@ -220,7 +220,7 @@ @@ -220,7 +220,7 @@
</div>
<div class="im_message_audio_player_wrap" ng-if="historyMessage.media.audio.url">
<audio my-audio-autoplay audio="historyMessage.media.audio" controls="controls">
<source ng-src="{{historyMessage.media.audio.url}}" type="audio/mpeg" />
<source bo-src="{{historyMessage.media.audio.url}}" type="audio/mpeg" />
<embed hidden="true" autostart="true" loop="false" src="{{historyMessage.media.audio.url}}" />
</audio>
</div>
@ -232,7 +232,7 @@ @@ -232,7 +232,7 @@
</a>
<div ng-switch-when="messageMediaContact">
<a ng-click="openUser(historyMessage.media.user.id)" class="im_message_contact_photo pull-left" ng-if="historyMessage.media.user">
<a bo-if="historyMessage.media.user" ng-click="openUser(historyMessage.media.user.id)" class="im_message_contact_photo pull-left">
<img
class="im_message_contact_photo"
my-load-thumb
@ -273,7 +273,7 @@ @@ -273,7 +273,7 @@
</div>
<div class="im_message_text" ng-if="historyMessage.message.length" ng-bind-html="historyMessage.richMessage"></div>
<div class="im_message_text" bo-if="historyMessage.message.length" ng-bind-html="historyMessage.richMessage"></div>
</div>
</div>

2
app/partials/settings_modal.html

@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
thumb="profile.photo"
/>
<div class="settings_profile_photo_change_wrap">
<div ng-if="photo.updating" class="settings_profile_photo_loading">Updating<span my-typing-dots></span></div>
<div ng-if="photo.updating" class="settings_profile_photo_loading">Updating<span my-loading-dots></span></div>
<div ng-if="!photo.updating">
<div class="settings_profile_photo_update_link">
<input my-file-upload type="file" multiple="false" class="im_attach_input" size="120" multiple="false" accept="image/x-png, image/png, image/gif, image/jpeg" />

321
app/vendor/bindonce/bindonce.js vendored

@ -0,0 +1,321 @@ @@ -0,0 +1,321 @@
(function () {
"use strict";
/**
* Bindonce - Zero watches binding for AngularJs
* @version v0.3.1
* @link https://github.com/Pasvaz/bindonce
* @author Pasquale Vazzana <pasqualevazzana@gmail.com>
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
var bindonceModule = angular.module('pasvaz.bindonce', []);
bindonceModule.directive('bindonce', function ()
{
var toBoolean = function (value)
{
if (value && value.length !== 0)
{
var v = angular.lowercase("" + value);
value = !(v === 'f' || v === '0' || v === 'false' || v === 'no' || v === 'n' || v === '[]');
}
else
{
value = false;
}
return value;
};
var msie = parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
if (isNaN(msie))
{
msie = parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
}
var bindonceDirective =
{
restrict: "AM",
controller: ['$scope', '$element', '$attrs', '$interpolate', function ($scope, $element, $attrs, $interpolate)
{
var showHideBinder = function (elm, attr, value)
{
var show = (attr === 'show') ? '' : 'none';
var hide = (attr === 'hide') ? '' : 'none';
elm.css('display', toBoolean(value) ? show : hide);
};
var classBinder = function (elm, value)
{
if (angular.isObject(value) && !angular.isArray(value))
{
var results = [];
angular.forEach(value, function (value, index)
{
if (value) results.push(index);
});
value = results;
}
if (value)
{
elm.addClass(angular.isArray(value) ? value.join(' ') : value);
}
};
var transclude = function (transcluder, scope)
{
transcluder.transclude(scope, function (clone)
{
var parent = transcluder.element.parent();
var afterNode = transcluder.element && transcluder.element[transcluder.element.length - 1];
var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
angular.forEach(clone, function (node)
{
parentNode.insertBefore(node, afterNextSibling);
});
});
};
var ctrl =
{
watcherRemover: undefined,
binders: [],
group: $attrs.boName,
element: $element,
ran: false,
addBinder: function (binder)
{
this.binders.push(binder);
// In case of late binding (when using the directive bo-name/bo-parent)
// it happens only when you use nested bindonce, if the bo-children
// are not dom children the linking can follow another order
if (this.ran)
{
this.runBinders();
}
},
setupWatcher: function (bindonceValue)
{
var that = this;
this.watcherRemover = $scope.$watch(bindonceValue, function (newValue)
{
if (newValue === undefined) return;
that.removeWatcher();
that.checkBindonce(newValue);
}, true);
},
checkBindonce: function (value)
{
var that = this, promise = (value.$promise) ? value.$promise.then : value.then;
// since Angular 1.2 promises are no longer
// undefined until they don't get resolved
if (typeof promise === 'function')
{
promise(function ()
{
that.runBinders();
});
}
else
{
that.runBinders();
}
},
removeWatcher: function ()
{
if (this.watcherRemover !== undefined)
{
this.watcherRemover();
this.watcherRemover = undefined;
}
},
runBinders: function ()
{
while (this.binders.length > 0)
{
var binder = this.binders.shift();
if (this.group && this.group != binder.group) continue;
var value = binder.scope.$eval((binder.interpolate) ? $interpolate(binder.value) : binder.value);
switch (binder.attr)
{
case 'boIf':
if (toBoolean(value))
{
transclude(binder, binder.scope.$new());
}
break;
case 'boSwitch':
var selectedTranscludes, switchCtrl = binder.controller[0];
if ((selectedTranscludes = switchCtrl.cases['!' + value] || switchCtrl.cases['?']))
{
binder.scope.$eval(binder.attrs.change);
angular.forEach(selectedTranscludes, function (selectedTransclude)
{
transclude(selectedTransclude, binder.scope.$new());
});
}
break;
case 'boSwitchWhen':
var ctrl = binder.controller[0];
ctrl.cases['!' + binder.attrs.boSwitchWhen] = (ctrl.cases['!' + binder.attrs.boSwitchWhen] || []);
ctrl.cases['!' + binder.attrs.boSwitchWhen].push({ transclude: binder.transclude, element: binder.element });
break;
case 'boSwitchDefault':
var ctrl = binder.controller[0];
ctrl.cases['?'] = (ctrl.cases['?'] || []);
ctrl.cases['?'].push({ transclude: binder.transclude, element: binder.element });
break;
case 'hide':
case 'show':
showHideBinder(binder.element, binder.attr, value);
break;
case 'class':
classBinder(binder.element, value);
break;
case 'text':
binder.element.text(value);
break;
case 'html':
binder.element.html(value);
break;
case 'style':
binder.element.css(value);
break;
case 'src':
binder.element.attr(binder.attr, value);
if (msie) binder.element.prop('src', value);
break;
case 'attr':
angular.forEach(binder.attrs, function (attrValue, attrKey)
{
var newAttr, newValue;
if (attrKey.match(/^boAttr./) && binder.attrs[attrKey])
{
newAttr = attrKey.replace(/^boAttr/, '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
newValue = binder.scope.$eval(binder.attrs[attrKey]);
binder.element.attr(newAttr, newValue);
}
});
break;
case 'href':
case 'alt':
case 'title':
case 'id':
case 'value':
binder.element.attr(binder.attr, value);
break;
}
}
this.ran = true;
}
};
return ctrl;
}],
link: function (scope, elm, attrs, bindonceController)
{
var value = attrs.bindonce && scope.$eval(attrs.bindonce);
if (value !== undefined)
{
bindonceController.checkBindonce(value);
}
else
{
bindonceController.setupWatcher(attrs.bindonce);
elm.bind("$destroy", bindonceController.removeWatcher);
}
}
};
return bindonceDirective;
});
angular.forEach(
[
{ directiveName: 'boShow', attribute: 'show' },
{ directiveName: 'boHide', attribute: 'hide' },
{ directiveName: 'boClass', attribute: 'class' },
{ directiveName: 'boText', attribute: 'text' },
{ directiveName: 'boBind', attribute: 'text' },
{ directiveName: 'boHtml', attribute: 'html' },
{ directiveName: 'boSrcI', attribute: 'src', interpolate: true },
{ directiveName: 'boSrc', attribute: 'src' },
{ directiveName: 'boHrefI', attribute: 'href', interpolate: true },
{ directiveName: 'boHref', attribute: 'href' },
{ directiveName: 'boAlt', attribute: 'alt' },
{ directiveName: 'boTitle', attribute: 'title' },
{ directiveName: 'boId', attribute: 'id' },
{ directiveName: 'boStyle', attribute: 'style' },
{ directiveName: 'boValue', attribute: 'value' },
{ directiveName: 'boAttr', attribute: 'attr' },
{ directiveName: 'boIf', transclude: 'element', terminal: true, priority: 1000 },
{ directiveName: 'boSwitch', require: 'boSwitch', controller: function () { this.cases = {}; } },
{ directiveName: 'boSwitchWhen', transclude: 'element', priority: 800, require: '^boSwitch' },
{ directiveName: 'boSwitchDefault', transclude: 'element', priority: 800, require: '^boSwitch' }
],
function (boDirective)
{
var childPriority = 200;
return bindonceModule.directive(boDirective.directiveName, function ()
{
var bindonceDirective =
{
priority: boDirective.priority || childPriority,
transclude: boDirective.transclude || false,
terminal: boDirective.terminal || false,
require: ['^bindonce'].concat(boDirective.require || []),
controller: boDirective.controller,
compile: function (tElement, tAttrs, transclude)
{
return function (scope, elm, attrs, controllers)
{
var bindonceController = controllers[0];
var name = attrs.boParent;
if (name && bindonceController.group !== name)
{
var element = bindonceController.element.parent();
bindonceController = undefined;
var parentValue;
while (element[0].nodeType !== 9 && element.length)
{
if ((parentValue = element.data('$bindonceController'))
&& parentValue.group === name)
{
bindonceController = parentValue;
break;
}
element = element.parent();
}
if (!bindonceController)
{
throw new Error("No bindonce controller: " + name);
}
}
bindonceController.addBinder(
{
element: elm,
attr: boDirective.attribute || boDirective.directiveName,
attrs: attrs,
value: attrs[boDirective.directiveName],
interpolate: boDirective.interpolate,
group: name,
transclude: transclude,
controller: controllers.slice(1),
scope: scope
});
};
}
};
return bindonceDirective;
});
})
})();
Loading…
Cancel
Save