5 angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap'])
7 .directive("egContextMenuItem", ['$timeout',function ($timeout) {
11 template: '<li><a ng-click="setContent(item.value,item.action)">{{item.label}}</a></li>',
12 scope: { item: '=', content: '=' },
13 controller: ['$scope','$element',
14 function ($scope , $element) {
15 if (!$scope.item.label) $scope.item.label = $scope.item.value;
16 if ($scope.item.divider) {
17 $element.style.borderTop = 'solid 1px';
20 $scope.setContent = function (v, a) {
22 if (a) replace_with = a($scope,$element,$scope.item.value,$scope.$parent.$parent.content);
24 $scope.$parent.$parent.$apply(function(){
25 $scope.$parent.$parent.content = replace_with
28 $($element).parent().css({display: 'none'});
35 .directive("egMarcEditEditable", ['$timeout', '$compile', '$document', function ($timeout, $compile, $document) {
39 template: '<input style="font-family: \'Lucida Console\', Monaco, monospace;" ng-model="content" size="{{content.length * 1.1}}" maxlength="{{max}}" class="" type="text"/>',
45 contextItemContainer: '@',
50 controller : ['$scope',
53 /* XXX Example, for testing. We'll get this from the tag-table services for realz
55 if (!$scope.contextItemContainer) {
56 $scope.contextItemContainer = "default_context";
57 $scope[$scope.contextItemContainer] = [
67 if ($scope.contextItemContainer)
68 $scope.item_container = $scope[$scope.contextItemContainer];
70 $scope.showContext = function (event) {
71 if ($scope.context_menu_element) {
72 console.log('Reshowing context menu...');
73 $($scope.context_menu_element).css({ display: 'block', top: event.pageY, left: event.pageX });
74 $('body').on('click.context_menu',function() {
75 $($scope.context_menu_element).css('display','none');
76 $('body').off('click.context_menu');
81 if (angular.isArray($scope.item_container)) { // we have a list of values or transforms
82 console.log('Showing context menu...');
85 '<ul class="dropdown-menu" role="menu">'+
86 '<eg-context-menu-item ng-repeat="item in item_container" item="item" content="content"/>'+
89 var tnode = angular.element(tmpl);
90 $document.find('body').append(tnode);
98 $scope.context_menu_element = tnode;
100 $timeout(function() {
101 var e = $compile(tnode)($scope);
105 $('body').on('click.context_menu',function() {
106 $(tnode).css('display','none');
107 $('body').off('click.context_menu');
118 link: function (scope, element, attrs) {
120 if (scope.onKeydown) element.bind('keydown', scope.onKeydown);
122 element.bind('change', function (e) { element.size = scope.max || parseInt(scope.content.length * 1.1) });
124 if (scope.contextItemContainer && angular.isArray(scope[scope.contextItemContainer]))
125 element.bind('contextmenu', scope.showContext);
130 .directive("egMarcEditSubfield", function () {
135 '<span><eg-marc-edit-editable '+
137 'class="marcsfcode" '+
139 'subfield="subfield" '+
140 'content="subfield[0]" '+
142 'on-keydown="onKeydown" '+
143 'id="r{{field.record.subfield(\'901\',\'c\')[1]}}f{{field.position}}s{{subfield[2]}}code" '+
145 '<span><eg-marc-edit-editable '+
147 'class="marcsfvalue" '+
149 'subfield="subfield" '+
150 'content="subfield[1]" '+
151 'on-keydown="onKeydown" '+
152 'id="r{{field.record.subfield(\'901\',\'c\')[1]}}f{{field.position}}s{{subfield[2]}}value" '+
155 scope: { field: "=", subfield: "=", onKeydown: '=' },
160 .directive("egMarcEditInd", function () {
164 template: '<span><eg-marc-edit-editable itype="ind" field="field" content="ind" max="1" on-keydown="onKeydown" id="r{{field.record.subfield(\'901\',\'c\')[1]}}f{{field.position}}i{{indNumber}}"/></span>',
165 scope: { ind : '=', field: '=', onKeydown: '=', indNumber: '@' },
170 .directive("egMarcEditTag", function () {
174 template: '<span><eg-marc-edit-editable itype="tag" field="field" content="tag" max="3" on-keydown="onKeydown" id="r{{field.record.subfield(\'901\',\'c\')[1]}}f{{field.position}}tag"/></span>',
175 scope: { tag : '=', field: '=', onKeydown: '=' },
180 .directive("egMarcEditDatafield", function () {
185 '<span><eg-marc-edit-tag class="marctag" field="field" tag="field.tag" on-keydown="onKeydown"/></span>'+
186 '<span><eg-marc-edit-ind class="marcind" field="field" ind="field.ind1" on-keydown="onKeydown" ind-number="1"/></span>'+
187 '<span><eg-marc-edit-ind class="marcind" field="field" ind="field.ind2" on-keydown="onKeydown" ind-number="2"/></span>'+
188 '<span><eg-marc-edit-subfield ng-repeat="subfield in field.subfields" subfield="subfield" field="field" on-keydown="onKeydown"/></span>'+
190 scope: { field: "=", onKeydown: '=' }
194 .directive("egMarcEditControlfield", function () {
199 '<span><eg-marc-edit-tag class="marctag" field="field" tag="field.tag" on-keydown="onKeydown"/></span>'+
200 '<span><eg-marc-edit-editable itype="cfld" field="field" class="marcdata" content="field.data" on-keydown="onKeydown" id="r{{field.record.subfield(\'901\',\'c\')[1]}}f{{field.position}}data"/></span>'+
202 scope: { field: "=", onKeydown: '=' }
206 .directive("egMarcEditLeader", function () {
211 '<span><eg-marc-edit-editable class="marctag" content="tag" on-keydown="onKeydown" id="leadertag" disabled="disabled"/></span>'+
212 '<span><eg-marc-edit-editable class="marcdata" itype="ldr" max="{{record.leader.length}}" content="record.leader" id="r{{record.subfield(\'901\',\'c\')[1]}}leaderdata" on-keydown="onKeydown"/></span>'+
214 controller : ['$scope',
215 function ( $scope ) {
219 scope: { record: "=", onKeydown: '=' }
223 /// TODO: fixed field editor and such
224 .directive("egMarcEditRecord", function () {
226 template: '<form ng-submit="saveRecord()">'+
227 '<div class="marcrecord">'+
228 '<div><eg-marc-edit-leader record="record" on-keydown="onKeydown"/></div>'+
229 '<div><eg-marc-edit-controlfield ng-repeat="field in controlfields" field="field" on-keydown="onKeydown"/></div>'+
230 '<div><eg-marc-edit-datafield ng-repeat="field in datafields" field="field" on-keydown="onKeydown"/></div>'+
232 '<button class="btn btn-default" type="submit">Save</button>'+
234 '<button class="btn btn-default" ng-click="seeBreaker()">Breaker</button>',
237 scope: { recordId : '=', maxUndo : '@' },
238 controller : ['$timeout','$scope','egCore',
239 function ( $timeout , $scope , egCore ) {
241 $scope.max_undo = $scope.maxUndo || 100;
242 $scope.record_undo_stack = [];
243 $scope.record_redo_stack = [];
244 $scope.in_undo = false;
245 $scope.in_redo = false;
246 $scope.record = new MARC.Record();
247 $scope.save_stack_depth = 0;
248 $scope.controlfields = [];
249 $scope.datafields = [];
251 $scope.onKeydown = function (event) {
252 var event_return = true;
254 if (event.which == 89 && event.ctrlKey) { // ctrl+y, redo
255 event_return = $scope.processRedo();
256 } else if (event.which == 90 && event.ctrlKey) { // ctrl+z, undo
257 event_return = $scope.processUndo();
258 } else { // Assumes only marc editor elements have IDs that can trigger this event handler.
259 $scope.current_event_target = $(event.target).attr('id');
260 if ($scope.current_event_target) {
261 $scope.current_event_target_cursor_pos =
262 event.target.selectionDirection=='backward' ?
263 event.target.selectionStart :
264 event.target.selectionEnd;
271 function setCaret() {
272 if ($scope.current_event_target) {
273 var element = $('#'+$scope.current_event_target).get(0);
275 element.setSelectionRange(
276 $scope.current_event_target_cursor_pos,
277 $scope.current_event_target_cursor_pos
279 $scope.current_event_target = null;
283 function loadRecord() {
284 return egCore.pcrud.retrieve(
285 'bre', $scope.recordId
286 ).then(function(rec) {
287 $scope.in_redo = true;
289 $scope.record = new MARC.Record({ marcxml : $scope.bre.marc() });
290 $scope.controlfields = $scope.record.fields.filter(function(f){ return f.isControlfield() });
291 $scope.datafields = $scope.record.fields.filter(function(f){ return !f.isControlfield() });
292 $scope.save_stack_depth = $scope.record_undo_stack.length;
296 $scope.$watch('record.toBreaker()', function (newVal, oldVal) {
297 if (!$scope.in_undo && !$scope.in_redo && oldVal != newVal) {
298 $scope.record_undo_stack.push({
300 target: $scope.current_event_target,
301 pos: $scope.current_event_target_cursor_pos
304 if ($scope.record_undo_stack.length != $scope.save_stack_depth) {
305 console.log('should get a listener... does not');
306 $('body').on('beforeunload', function(){
307 return 'There is unsaved data in this record.'
310 $('body').off('beforeunload');
314 if ($scope.record_undo_stack.length > $scope.max_undo)
315 $scope.record_undo_stack.shift();
317 console.log('undo stack is ' + $scope.record_undo_stack.length + ' deep');
318 $scope.in_redo = false;
319 $scope.in_undo = false;
322 $scope.processUndo = function () {
323 if ($scope.record_undo_stack.length) {
324 $scope.in_undo = true;
326 var undo_item = $scope.record_undo_stack.pop();
327 $scope.record_redo_stack.push(undo_item);
329 $scope.record = new MARC.Record({ marcbreaker : undo_item.breaker });
330 $scope.controlfields = $scope.record.fields.filter(function(f){ return f.isControlfield() });
331 $scope.datafields = $scope.record.fields.filter(function(f){ return !f.isControlfield() });
333 $scope.current_event_target = undo_item.target;
334 $scope.current_event_target_cursor_pos = undo_item.pos;
335 console.log('Undo targeting ' + $scope.current_event_target + ' position ' + $scope.current_event_target_cursor_pos);
337 $timeout(function(){$scope.$digest()}).then(setCaret);
344 $scope.processRedo = function () {
345 if ($scope.record_redo_stack.length) {
346 $scope.in_redo = true;
348 var redo_item = $scope.record_redo_stack.pop();
349 $scope.record_undo_stack.push(redo_item);
351 $scope.record = new MARC.Record({ marcbreaker : redo_item.breaker });
352 $scope.controlfields = $scope.record.fields.filter(function(f){ return f.isControlfield() });
353 $scope.datafields = $scope.record.fields.filter(function(f){ return !f.isControlfield() });
355 $scope.current_event_target = redo_item.target;
356 $scope.current_event_target_cursor_pos = redo_item.pos;
357 console.log('Redo targeting ' + $scope.current_event_target + ' position ' + $scope.current_event_target_cursor_pos);
359 $timeout(function(){$scope.$digest()}).then(setCaret);
366 $scope.saveRecord = function () {
367 $scope.bre.marc($scope.record.toXmlString());
368 return egCore.pcrud.update(
373 $scope.seeBreaker = function () {
374 alert($scope.record.toBreaker());
377 $scope.$watch('recordId',
378 function(newVal, oldVal) {
379 if (newVal && newVal !== oldVal) {